Bug 475578 - Implement Extended DSA as defined in FIPS 186-3
authorrrelyea%redhat.com
Mon, 25 Jun 2012 17:30:17 +0000
changeset 10392 884b916c47fee8a8bf93920b6a6afb4e64aa4a54
parent 10391 6f32bae686f9eaeb42fdd2b5bd36f887b6184746
child 10393 0b2bfb8edac19a297baf86e946392179bb423d19
push idunknown
push userunknown
push dateunknown
bugs475578
Bug 475578 - Implement Extended DSA as defined in FIPS 186-3 patch 4 of 7 r=wtc
security/nss/lib/freebl/pqg.c
security/nss/lib/nss/nss.def
security/nss/lib/pk11wrap/pk11obj.c
security/nss/lib/pk11wrap/pk11pqg.c
security/nss/lib/pk11wrap/pk11pqg.h
security/nss/lib/pk11wrap/pk11pub.h
security/nss/lib/pk11wrap/pk11slot.c
security/nss/lib/pk11wrap/pk11util.c
--- a/security/nss/lib/freebl/pqg.c
+++ b/security/nss/lib/freebl/pqg.c
@@ -23,17 +23,17 @@
 #include "secmpi.h"
 #include "sechash.h"
 
 #define MAX_ITERATIONS 1000  /* Maximum number of iterations of primegen */
 
 typedef enum {
     FIPS186_1_TYPE,		/* Probablistic */
     FIPS186_3_TYPE,		/* Probablistic */
-    FIPS186_3_ST_TYPE		/* Shawne-Taylor provable */
+    FIPS186_3_ST_TYPE		/* Shawe-Taylor provable */
 } pqgGenType;
 
 /*
  * These test iterations are quite a bit larger than we previously had.
  * This is because FIPS 186-3 is worried about the primes in PQG generation.
  * It may be possible to purposefully construct composites which more 
  * iterations of Miller-Rabin than the for your normal randomly selected 
  * numbers.There are 3 ways to counter this: 1) use one of the cool provably 
@@ -432,17 +432,17 @@ cleanup:
 **  This generates a provable prime from two smaller prime. The resulting
 **  prime p will have q0 as a multiple of p-1. q0 can be 1.
 **
 ** This implments steps 4 thorough 22 of FIPS 186-3 A.1.2.1 and
 **                steps 16 through 34 of FIPS 186-2 C.6
 */
 #define MAX_ST_SEED_BITS HASH_LENGTH_MAX*BITS_PER_BYTE
 SECStatus
-makePrimefromPrimesShawneTaylor(
+makePrimefromPrimesShaweTaylor(
       HASH_HashType hashtype,	/* selected Hashing algorithm */
       unsigned int  length,     /* input. Length of prime in bits. */
       mp_int    *   c0,         /* seed prime */
       mp_int    *   q,          /* sub prime, can be 1 */
       mp_int    *   prime,      /* output.  */
       SECItem   *   prime_seed, /* input/output.  */
       int       *   prime_gen_counter) /* input/output.  */
 {
@@ -666,17 +666,17 @@ cleanup:
 }
 
 /*
 **  Perform steps from  FIPS 186-3, Appendix C.6
 **
 **  This generates a provable prime from a seed
 */
 SECStatus
-makePrimefromSeedShawneTaylor(
+makePrimefromSeedShaweTaylor(
       HASH_HashType hashtype,	/* selected Hashing algorithm */
       unsigned int  length,     /* input.  Length of prime in bits. */
 const SECItem   *   input_seed,       /* input.  */
       mp_int    *   prime,      /* output.  */
       SECItem   *   prime_seed, /* output.  */
       int       *   prime_gen_counter) /* output.  */
 {
     mp_int c;
@@ -707,24 +707,24 @@ const SECItem   *   input_seed,       /*
     /* Step 2. if length >= 33 then goto step 14 */
     if (length >= 33) {
 	mp_zero(&one);
 	CHECK_MPI_OK( mp_add_d(&one, (mp_digit) 1, &one) );
 
 	/* Step 14 (status, c0, prime_seed, prime_gen_counter) =
 	** (ST_Random_Prime((ceil(length/2)+1, input_seed)
 	*/
-	rv = makePrimefromSeedShawneTaylor(hashtype, (length+1)/2+1,
+	rv = makePrimefromSeedShaweTaylor(hashtype, (length+1)/2+1,
 			input_seed, &c0, prime_seed, prime_gen_counter);
 	/* Step 15 if FAILURE is returned, return (FAILURE, 0, 0, 0). */
 	if (rv != SECSuccess) {
 	    goto cleanup;
 	}
 	/* Steps 16-34 */
-	rv = makePrimefromPrimesShawneTaylor(hashtype,length, &c0, &one,
+	rv = makePrimefromPrimesShaweTaylor(hashtype,length, &c0, &one,
 		prime, prime_seed, prime_gen_counter);
 	goto cleanup; /* we're done, one way or the other */
     }
     /* Step 3 prime_seed = input_seed */
     CHECK_SEC_OK(SECITEM_CopyItem(NULL, prime_seed, input_seed));
     /* Step 4 prime_gen_count = 0 */
     *prime_gen_counter = 0;
 
@@ -876,25 +876,25 @@ const SECItem   *   seed,       /* input
 	}
 	if (mp_cmp(Q,Q_) == 0) {
 	    *hashtypePtr = hashtype;
 	    *typePtr = FIPS186_3_TYPE;
 	    return SECSuccess;
 	}
     }
     /*
-     * OK finally try FIPS186_3 Shawne-Taylor 
+     * OK finally try FIPS186_3 Shawe-Taylor 
      */
     firstseed = *seed;
     firstseed.len = seed->len/3;
     for (hashtype = getFirstHash(L,N); hashtype != HASH_AlgTOTAL; 
 					hashtype=getNextHash(hashtype)) {
 	int count;
 
-	rv = makePrimefromSeedShawneTaylor(hashtype, N, &firstseed, Q_, 
+	rv = makePrimefromSeedShaweTaylor(hashtype, N, &firstseed, Q_, 
 		&qseed, &count);
 	if (rv != SECSuccess) {
 	    continue;
 	}
 	if (mp_cmp(Q,Q_) == 0) {
 	    /* check qseed as well... */
 	    int offset = seed->len - qseed.len;
 	    if ((offset < 0) || 
@@ -1608,20 +1608,20 @@ PQG_VerifyParams(const PQGParams *params
 	/*
 	 * now complete FIPS 186-3 A.1.2.1.2. Step 1 was completed
 	 * above in our initial checks, Step 2 was completed by
 	 * findQfromSeed */
 
 	/* Step 3 (status, c0, prime_seed, prime_gen_counter) =
 	** (ST_Random_Prime((ceil(length/2)+1, input_seed)
 	*/
-	CHECK_SEC_OK( makePrimefromSeedShawneTaylor(hashtype, (L+1)/2+1,
+	CHECK_SEC_OK( makePrimefromSeedShaweTaylor(hashtype, (L+1)/2+1,
 			&qseed, &p0, &pseed_, &pgen_counter) );
 	/* Steps 4-22 FIPS 186-3 appendix A.1.2.1.2 */
-	CHECK_SEC_OK( makePrimefromPrimesShawneTaylor(hashtype, L, 
+	CHECK_SEC_OK( makePrimefromPrimesShaweTaylor(hashtype, L, 
 		&p0, &Q_, &P_, &pseed_, &pgen_counter) );
 	CHECKPARAM( mp_cmp(&P, &P_) == 0 );
 	/* make sure pseed wasn't tampered with (since it is part of 
 	 * calculating G) */
 	CHECKPARAM( SECITEM_CompareItem(&pseed, &pseed_) == SECEqual );
     } else if (vfy->counter == -1) {
 	/* If counter is set to -1, we are really only verifying G, skip
 	 * the remainder of the checks for P */
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -995,16 +995,19 @@ NSS_GetVersion;
 ;+       *;
 ;+};
 ;+NSS_3.13.2 { 	# NSS 3.13.2 release
 ;+    global:
 PK11_ImportEncryptedPrivateKeyInfoAndReturnKey;
 ;+    local:
 ;+       *;
 ;+};
-;+NSS_3.14 {    # NSS 3.14 release
+;+NSS_3.14 { 	# NSS 3.14 release
 ;+    global:
 CERT_CheckOCSPStatus;
 CERT_DecodeOCSPRequest;
 CERT_GetEncodedOCSPResponse;
+PK11_GetBestSlotWithKeySize;
+PK11_GetBestSlotMultipleWithKeySize;
+PK11_PQG_ParamGenV2;
 ;+    local:
 ;+       *;
 ;+};
--- a/security/nss/lib/pk11wrap/pk11obj.c
+++ b/security/nss/lib/pk11wrap/pk11obj.c
@@ -514,47 +514,56 @@ pk11_backupGetSignLength(SECKEYPrivateKe
 
 /*
  * get the length of a signature object based on the key
  */
 int
 PK11_SignatureLen(SECKEYPrivateKey *key)
 {
     int val;
-    CK_ATTRIBUTE theTemplate = { CKA_EC_PARAMS, NULL, 0 };
-    SECItem params = {siBuffer, NULL, 0};
+    SECItem attributeItem = {siBuffer, NULL, 0};
+    SECStatus rv;
     int length; 
 
     switch (key->keyType) {
     case rsaKey:
 	val = PK11_GetPrivateModulusLen(key);
 	if (val == -1) {
 	    return pk11_backupGetSignLength(key);
 	}
 	return (unsigned long) val;
 	
     case fortezzaKey:
+	return 40;
+
     case dsaKey:
-	return 40;
+        rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_SUBPRIME, 
+				NULL, &attributeItem);
+        if (rv == SECSuccess) {
+	    length = attributeItem.len;
+	    if ((length > 0) && attributeItem.data[0] == 0) {
+		length--;
+	    }
+	    PORT_Free(attributeItem.data);
+	    return length*2;
+	}
+	return pk11_backupGetSignLength(key);
+
     case ecKey:
-	if (PK11_GetAttributes(NULL, key->pkcs11Slot, key->pkcs11ID,
-			       &theTemplate, 1) == CKR_OK) {
-	    if (theTemplate.pValue != NULL) {
-	        params.len = theTemplate.ulValueLen;
-		params.data = (unsigned char *) theTemplate.pValue;
-	        length = SECKEY_ECParamsToBasePointOrderLen(&params);
-	        PORT_Free(theTemplate.pValue);
-		if (length == 0) {
-		    return pk11_backupGetSignLength(key);
-		}
+        rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_EC_PARAMS, 
+				NULL, &attributeItem);
+	if (rv == SECSuccess) {
+	    length = SECKEY_ECParamsToBasePointOrderLen(&attributeItem);
+	    PORT_Free(attributeItem.data);
+	    if (length != 0) {
 		length = ((length + 7)/8) * 2;
 		return length;
 	    }
 	}
-	break;
+	return pk11_backupGetSignLength(key);
     default:
 	break;
     }
     PORT_SetError( SEC_ERROR_INVALID_KEY );
     return 0;
 }
 
 /*
@@ -657,17 +666,32 @@ PK11_Verify(SECKEYPublicKey *key, SECIte
     CK_MECHANISM mech = {0, NULL, 0 };
     PRBool owner = PR_TRUE;
     CK_SESSION_HANDLE session;
     CK_RV crv;
 
     mech.mechanism = PK11_MapSignKeyType(key->keyType);
 
     if (slot == NULL) {
-	slot = PK11_GetBestSlot(mech.mechanism,wincx);
+	if ((mech.mechanism == CKM_DSA) && 
+				/* 129 is 1024 bits translated to bytes and
+				 * padded with an optional '0' to maintain a
+				 * positive sign */
+				(key->u.dsa.params.prime.len > 129)) {
+	    /* we need to get a slot that not only can do DSA, but can do DSA2
+	     * key lengths */
+	    unsigned int length = key->u.dsa.params.prime.len;
+	    if (length > 0 && key->u.dsa.params.prime.data[0] == 0) {
+		length --;
+	    }
+	    slot = PK11_GetBestSlotWithKeySize(mech.mechanism, 
+						length*BITS_PER_BYTE, wincx);
+	} else {
+	    slot = PK11_GetBestSlot(mech.mechanism,wincx);
+	}
        
 	if (slot == NULL) {
 	    PORT_SetError( SEC_ERROR_NO_MODULE );
 	    return SECFailure;
 	}
 	id = PK11_ImportPublicKey(slot,key,PR_FALSE);
             
     } else {
--- a/security/nss/lib/pk11wrap/pk11pqg.c
+++ b/security/nss/lib/pk11wrap/pk11pqg.c
@@ -10,23 +10,43 @@
 #include "secmodi.h"
 #include "secmodti.h"
 #include "pkcs11t.h"
 #include "pk11pqg.h"
 #include "secerr.h"
 
 
 /* Generate PQGParams and PQGVerify structs.
- * Length of P specified by j.  Length of h will match length of P.
+ * Length of P specified by L.
+ *   if L is greater than 1024 then the resulting verify parameters will be
+ *   DSA2.
+ * Length of Q specified by N. If zero, The PKCS #11 module will
+ *   pick an appropriately sized Q for P. If N is specified and L = 1024, then
+ *   the resulting verify parameters will be DSA2, Otherwise DSA1 parameters 
+ *   will be returned.
  * Length of SEED in bytes specified in seedBytes.
- * seedBbytes must be in the range [20..255] or an error will result.
+ *
+ * The underlying PKCS #11 module will check the values for L, N, 
+ * and seedBytes. The rules for softoken are:
+ * 
+ * If L <= 1024, then L must be between 512 and 1024 in increments of 64 bits.
+ * If L <= 1024, then N must be 0 or 160.
+ * If L >= 1024, then L and N must match the following table:
+ *   L=1024   N=0 or 160
+ *   L=2048   N=0 or 224
+ *   L=2048   N=256
+ *   L=3072   N=0 or 256
+ * if L <= 1024
+ *   seedBbytes must be in the range [20..256].
+ * if L >= 1024
+ *   seedBbytes must be in the range [20..L/16].
  */
 extern SECStatus
-PK11_PQG_ParamGenSeedLen( unsigned int j, unsigned int seedBytes,
-				 PQGParams **pParams, PQGVerify **pVfy)
+PK11_PQG_ParamGenV2(unsigned int L, unsigned int N,
+	 unsigned int seedBytes, PQGParams **pParams, PQGVerify **pVfy)
 {
     PK11SlotInfo *slot = NULL;
     CK_ATTRIBUTE genTemplate[5];
     CK_ATTRIBUTE *attrs = genTemplate;
     int count = sizeof(genTemplate)/sizeof(genTemplate[0]);
     CK_MECHANISM mechanism;
     CK_OBJECT_HANDLE objectID = CK_INVALID_HANDLE;
     CK_RV crv;
@@ -35,46 +55,77 @@ PK11_PQG_ParamGenSeedLen( unsigned int j
 	{ CKA_SUBPRIME, NULL, 0 },
 	{ CKA_BASE, NULL, 0 },
     };
     CK_ATTRIBUTE vTemplate[] = {
 	{ CKA_NETSCAPE_PQG_COUNTER, NULL, 0 },
 	{ CKA_NETSCAPE_PQG_SEED, NULL, 0 },
 	{ CKA_NETSCAPE_PQG_H, NULL, 0 },
     };
+    CK_ULONG primeBits = L;
+    CK_ULONG subPrimeBits = N;
     int pTemplateCount = sizeof(pTemplate)/sizeof(pTemplate[0]);
     int vTemplateCount = sizeof(vTemplate)/sizeof(vTemplate[0]);
     PRArenaPool *parena = NULL;
     PRArenaPool *varena = NULL;
     PQGParams *params = NULL;
     PQGVerify *verify = NULL;
-    CK_ULONG primeBits = PQG_INDEX_TO_PBITS(j);
     CK_ULONG seedBits = seedBytes*8;
 
     *pParams = NULL;
     *pVfy =  NULL;
 
     if (primeBits == (CK_ULONG)-1) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	goto loser;
     }
     PK11_SETATTRS(attrs, CKA_PRIME_BITS,&primeBits,sizeof(primeBits)); attrs++;
+    if (subPrimeBits != 0) {
+    	PK11_SETATTRS(attrs, CKA_SUB_PRIME_BITS, 
+				&subPrimeBits, sizeof(subPrimeBits)); attrs++;
+    }
     if (seedBits != 0) {
     	PK11_SETATTRS(attrs, CKA_NETSCAPE_PQG_SEED_BITS, 
 					&seedBits, sizeof(seedBits)); attrs++;
     }
     count = attrs - genTemplate;
     PR_ASSERT(count <= sizeof(genTemplate)/sizeof(CK_ATTRIBUTE));
 
     slot = PK11_GetInternalSlot();
     if (slot == NULL) {
 	/* set error */
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);/* shouldn't happen */
 	goto loser;
     }
 
+    /* make sure the internal slot can handle DSA2 type parameters. */
+    if (primeBits > 1024) {
+	CK_MECHANISM_INFO mechanism_info;
+
+	crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
+			CKM_DSA_PARAMETER_GEN, &mechanism_info);
+	/* a bug in the old softoken left CKM_DSA_PARAMETER_GEN off of the
+	 * mechanism List. If we get a failure asking for this value, we know
+	 * it can't handle DSA2 */
+	if ((crv != CKR_OK) || (mechanism_info.ulMaxKeySize < primeBits)) {
+	    PK11_FreeSlot(slot);
+	    slot = PK11_GetBestSlotWithKeySize(CKM_DSA_PARAMETER_GEN, 
+						primeBits, NULL);
+	    if (slot == NULL) {
+		PORT_SetError(SEC_ERROR_NO_TOKEN); /* can happen */
+		goto loser;
+	    }
+	    /* ditch seedBits in this case, they are NSS specific and at
+	     * this point we have a token that claims to handle DSA2 */
+	    if (seedBits) {
+		attrs--;
+	    }
+	}
+    }
+
     /* Initialize the Key Gen Mechanism */
     mechanism.mechanism = CKM_DSA_PARAMETER_GEN;
     mechanism.pParameter = NULL;
     mechanism.ulParameterLen = 0;
 
     PK11_EnterSlotMonitor(slot);
     crv = PK11_GETTAB(slot)->C_GenerateKey(slot->session,
 			 &mechanism, genTemplate, count, &objectID);
@@ -161,23 +212,37 @@ loser:
     }
     if (slot) {
 	PK11_FreeSlot(slot);
     }
     return SECFailure;
 }
 
 /* Generate PQGParams and PQGVerify structs.
+ * Length of P specified by j.  Length of h will match length of P.
+ * Length of SEED in bytes specified in seedBytes.
+ * seedBbytes must be in the range [20..255] or an error will result.
+ */
+extern SECStatus
+PK11_PQG_ParamGenSeedLen( unsigned int j, unsigned int seedBytes,
+				 PQGParams **pParams, PQGVerify **pVfy)
+{
+    unsigned int primeBits = PQG_INDEX_TO_PBITS(j);
+    return PK11_PQG_ParamGenV2(primeBits, 0, seedBytes, pParams, pVfy);
+}
+
+/* Generate PQGParams and PQGVerify structs.
  * Length of seed and length of h both equal length of P. 
  * All lengths are specified by "j", according to the table above.
  */
 extern SECStatus
 PK11_PQG_ParamGen(unsigned int j, PQGParams **pParams, PQGVerify **pVfy)
 {
-    return PK11_PQG_ParamGenSeedLen(j, 0, pParams, pVfy);
+    unsigned int primeBits = PQG_INDEX_TO_PBITS(j);
+    return PK11_PQG_ParamGenV2(primeBits, 0, 0, pParams, pVfy);
 }
 
 /*  Test PQGParams for validity as DSS PQG values.
  *  If vfy is non-NULL, test PQGParams to make sure they were generated
  *       using the specified seed, counter, and h values.
  *
  *  Return value indicates whether Verification operation ran successfully
  *  to completion, but does not indicate if PQGParams are valid or not.
@@ -214,26 +279,33 @@ PK11_PQG_VerifyParams(const PQGParams *p
 
     attrs = keyTempl;
     PK11_SETATTRS(attrs, CKA_CLASS, &class, sizeof(class)); attrs++;
     PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++;
     PK11_SETATTRS(attrs, CKA_PRIME, params->prime.data, 
 						params->prime.len); attrs++;
     PK11_SETATTRS(attrs, CKA_SUBPRIME, params->subPrime.data, 
 						params->subPrime.len); attrs++;
-    PK11_SETATTRS(attrs, CKA_BASE,params->base.data,params->base.len); attrs++;
+    if (params->base.len) {
+        PK11_SETATTRS(attrs, CKA_BASE,params->base.data,params->base.len);
+	 attrs++;
+    }
     PK11_SETATTRS(attrs, CKA_TOKEN, &ckfalse, sizeof(ckfalse)); attrs++;
     if (vfy) {
-	counter = vfy->counter;
-	PK11_SETATTRS(attrs, CKA_NETSCAPE_PQG_COUNTER, 
+	if (vfy->counter != -1) {
+	    counter = vfy->counter;
+	    PK11_SETATTRS(attrs, CKA_NETSCAPE_PQG_COUNTER, 
 			&counter, sizeof(counter)); attrs++;
+	}
 	PK11_SETATTRS(attrs, CKA_NETSCAPE_PQG_SEED, 
 			vfy->seed.data, vfy->seed.len); attrs++;
-	PK11_SETATTRS(attrs, CKA_NETSCAPE_PQG_H, 
+	if (vfy->h.len) {
+	    PK11_SETATTRS(attrs, CKA_NETSCAPE_PQG_H, 
 			vfy->h.data, vfy->h.len); attrs++;
+	}
     }
 
     keyCount = attrs - keyTempl;
     PORT_Assert(keyCount <= sizeof(keyTempl)/sizeof(keyTempl[0]));
 
 
     slot = PK11_GetInternalSlot();
     if (slot == NULL) {
--- a/security/nss/lib/pk11wrap/pk11pqg.h
+++ b/security/nss/lib/pk11wrap/pk11pqg.h
@@ -22,42 +22,61 @@ extern SECStatus PK11_PQG_ParamGen(unsig
 /* Generate PQGParams and PQGVerify structs.
  * Length of P specified by j.  Length of h will match length of P.
  * Length of SEED in bytes specified in seedBytes.
  * seedBbytes must be in the range [20..255] or an error will result.
  */
 extern SECStatus PK11_PQG_ParamGenSeedLen( unsigned int j, 
 	unsigned int seedBytes, PQGParams **pParams, PQGVerify **pVfy);
 
+
+/* Generate PQGParams and PQGVerify structs.
+ * Length of P specified by L.
+ *   if L is greater than 1024 then the resulting verify parameters will be
+ *   DSA2.
+ * Length of Q specified by N. If zero, The PKCS #11 module will
+ *   pick an appropriately sized Q for L. If N is specified and L = 1024, then
+ *   the resulting verify parameters will be DSA2, Otherwise DSA1 parameters 
+ *   will be returned.
+ * Length of SEED in bytes specified in seedBytes.
+ *
+ * The underlying PKCS #11 module will check the values for L, N, 
+ * and seedBytes. The rules for softoken are:
+ * 
+ * If L <= 1024, then L must be between 512 and 1024 in increments of 64 bits.
+ * If L <= 1024, then N must be 0 or 160.
+ * If L >= 1024, then L and N must match the following table:
+ *   L=1024   N=0 or 160
+ *   L=2048   N=0 or 224
+ *   L=2048   N=256
+ *   L=3072   N=0 or 256
+ * if L <= 1024
+ *   seedBbytes must be in the range [20..256].
+ * if L >= 1024
+ *   seedBbytes must be in the range [20..L/16].
+ */
+extern SECStatus
+PK11_PQG_ParamGenV2(unsigned int L, unsigned int N, unsigned int seedBytes,
+		    PQGParams **pParams, PQGVerify **pVfy);
+
 /*  Test PQGParams for validity as DSS PQG values.
  *  If vfy is non-NULL, test PQGParams to make sure they were generated
  *       using the specified seed, counter, and h values.
  *
  *  Return value indicates whether Verification operation ran successfully
  *  to completion, but does not indicate if PQGParams are valid or not.
  *  If return value is SECSuccess, then *pResult has these meanings:
  *       SECSuccess: PQGParams are valid.
  *       SECFailure: PQGParams are invalid.
  *
  * Verify the following 12 facts about PQG counter SEED g and h
- * 1.  Q is 160 bits long.
- * 2.  P is one of the 9 valid lengths.
- * 3.  G < P
- * 4.  P % Q == 1
- * 5.  Q is prime
- * 6.  P is prime
- * Steps 7-12 are done only if the optional PQGVerify is supplied.
- * 7.  counter < 4096
- * 8.  g >= 160 and g < 2048   (g is length of seed in bits)
- * 9.  Q generated from SEED matches Q in PQGParams.
- * 10. P generated from (L, counter, g, SEED, Q) matches P in PQGParams.
- * 11. 1 < h < P-1
- * 12. G generated from h matches G in PQGParams.
+ * These tests are specified in FIPS 186-3 Appendix A.1.1.1, A.1.1.3, and A.2.2
+ * PQG_VerifyParams in softoken/freebl will automatically choose the 
+ * appropriate test.
  */
-
 extern SECStatus PK11_PQG_VerifyParams(const PQGParams *params, 
                                     const PQGVerify *vfy, SECStatus *result);
 extern void PK11_PQG_DestroyParams(PQGParams *params);
 extern void PK11_PQG_DestroyVerify(PQGVerify *vfy);
 
 /**************************************************************************
  *  Return a pointer to a new PQGParams struct that is constructed from   *
  *  copies of the arguments passed in.                                    *
--- a/security/nss/lib/pk11wrap/pk11pub.h
+++ b/security/nss/lib/pk11wrap/pk11pub.h
@@ -142,19 +142,23 @@ SECMODModule *PK11_GetModule(PK11SlotInf
 
 /*********************************************************************
  *            Slot mapping utility functions.
  *********************************************************************/
 PRBool PK11_IsPresent(PK11SlotInfo *slot);
 PRBool PK11_DoesMechanism(PK11SlotInfo *slot, CK_MECHANISM_TYPE type);
 PK11SlotList * PK11_GetAllTokens(CK_MECHANISM_TYPE type,PRBool needRW,
 					PRBool loadCerts, void *wincx);
+PK11SlotInfo *PK11_GetBestSlotMultipleWithKeySize(CK_MECHANISM_TYPE *type, 
+			  unsigned long *keySize, int count, void *wincx);
 PK11SlotInfo *PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type, int count,
 							void *wincx);
 PK11SlotInfo *PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx);
+PK11SlotInfo *PK11_GetBestSlotWithKeySize(CK_MECHANISM_TYPE type, 
+					unsigned long keySize, void *wincx);
 CK_MECHANISM_TYPE PK11_GetBestWrapMechanism(PK11SlotInfo *slot);
 int PK11_GetBestKeyLength(PK11SlotInfo *slot, CK_MECHANISM_TYPE type);
 
 /*
  * Open a new database using the softoken. The caller is responsible for making
  * sure the module spec is correct and usable. The caller should ask for one
  * new database per call if the caller wants to get meaningful information
  * about the new database.
--- a/security/nss/lib/pk11wrap/pk11slot.c
+++ b/security/nss/lib/pk11wrap/pk11slot.c
@@ -1952,22 +1952,26 @@ PK11_GetPrivateKeyTokens(CK_MECHANISM_TY
 	    continue;
 	}
     }
     return list;
 }
 
 
 /*
- * find the best slot which supports the given
- * Mechanism. In normal cases this should grab the first slot on the list
- * with no fuss.
+ * Find the best slot which supports the given set of mechanisms and key sizes.
+ * In normal cases this should grab the first slot on the list with no fuss.
+ * The size array is presumed to match one for one with the mechanism type 
+ * array, which allows you to specify the required key size for each
+ * mechanism in the list. Whether key size is in bits or bytes is mechanism
+ * dependent. Typically
  */
 PK11SlotInfo *
-PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type, int mech_count, void *wincx)
+PK11_GetBestSlotMultipleWithKeySize(CK_MECHANISM_TYPE *type, 
+                              unsigned long *size, int mech_count, void *wincx)
 {
     PK11SlotList *list = NULL;
     PK11SlotListElement *le ;
     PK11SlotInfo *slot = NULL;
     PRBool freeit = PR_FALSE;
     PRBool listNeedLogin = PR_FALSE;
     int i;
     SECStatus rv;
@@ -2008,16 +2012,30 @@ PK11_GetBestSlotMultiple(CK_MECHANISM_TY
 			 	le = PK11_GetNextSafe(list,le,PR_TRUE)) {
 	if (PK11_IsPresent(le->slot)) {
 	    PRBool doExit = PR_FALSE;
 	    for (i=0; i < mech_count; i++) {
 	    	if (!PK11_DoesMechanism(le->slot,type[i])) {
 		    doExit = PR_TRUE;
 		    break;
 		}
+		if (size && size[i]) {
+		    CK_MECHANISM_INFO mechanism_info;
+    		    CK_RV crv = PK11_GETTAB(le->slot)->C_GetMechanismInfo(
+				slot->slotID, type[i], &mechanism_info);
+		    if (crv != CKR_OK 
+			|| (mechanism_info.ulMinKeySize > size[i])
+			|| (mechanism_info.ulMaxKeySize < size[i]) ) {
+			/* Token can do mechanism, but not at the key size we
+			 * want */
+			doExit = PR_TRUE;
+			break;
+		    }
+		}
+		    
 	    }
 	    if (doExit) continue;
 	      
 	    if (listNeedLogin && le->slot->needLogin) {
 		rv = PK11_Authenticate(le->slot,PR_TRUE,wincx);
 		if (rv != SECSuccess) continue;
 	    }
 	    slot = le->slot;
@@ -2029,21 +2047,34 @@ PK11_GetBestSlotMultiple(CK_MECHANISM_TY
     }
     if (freeit) { PK11_FreeSlotList(list); }
     if (PORT_GetError() == 0) {
 	PORT_SetError(SEC_ERROR_NO_TOKEN);
     }
     return NULL;
 }
 
+PK11SlotInfo *
+PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type, int mech_count, void *wincx)
+{
+    return PK11_GetBestSlotMultipleWithKeySize(type, NULL, mech_count, wincx);
+}
+
 /* original get best slot now calls the multiple version with only one type */
 PK11SlotInfo *
 PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx)
 {
-    return PK11_GetBestSlotMultiple(&type, 1, wincx);
+    return PK11_GetBestSlotMultipleWithKeySize(&type, NULL, 1, wincx);
+}
+
+PK11SlotInfo *
+PK11_GetBestSlotWithKeySize(CK_MECHANISM_TYPE type, unsigned long keySize, 
+			void *wincx)
+{
+    return PK11_GetBestSlotMultipleWithKeySize(&type, &keySize, 1, wincx);
 }
 
 int
 PK11_GetBestKeyLength(PK11SlotInfo *slot,CK_MECHANISM_TYPE mechanism)
 {
     CK_MECHANISM_INFO mechanism_info;
     CK_RV crv;
 
--- a/security/nss/lib/pk11wrap/pk11util.c
+++ b/security/nss/lib/pk11wrap/pk11util.c
@@ -1077,17 +1077,17 @@ secmod_HandleWaitForSlotEvent(SECMODModu
 		PZ_Lock(mod->refLock);
 		mod->evControlMask &= ~SECMOD_END_WAIT;
 		PZ_Unlock(mod->refLock);
 		return PK11_ReferenceSlot(slot);
 	    }
 	}
 	SECMOD_ReleaseReadLock(moduleLock);
 	/* if everything was perm modules, don't lock up forever */
-	if (!removableSlotsFound) {
+	if ((mod->slotCount !=0) && !removableSlotsFound) {
 	    error =SEC_ERROR_NO_SLOT_SELECTED;
 	    PZ_Lock(mod->refLock);
 	    break;
 	}
 	if (flags & CKF_DONT_BLOCK) {
 	    PZ_Lock(mod->refLock);
 	    break;
 	}
@@ -1246,16 +1246,19 @@ SECMOD_HasRemovableSlots(SECMODModule *m
 	PK11SlotInfo *slot = mod->slots[i];
 	/* perm modules are not inserted or removed */
 	if (slot->isPerm) {
 	    continue;
 	}
 	ret = PR_TRUE;
 	break;
     }
+    if (mod->slotCount == 0 ) {
+	ret = PR_TRUE;
+    }
     SECMOD_ReleaseReadLock(moduleLock);
     return ret;
 }
 
 /*
  * helper function to actually create and destroy user defined slots
  */
 static SECStatus