Blame SOURCES/nss-softokn-fips-update.patch

ddf7d0
diff --git a/lib/freebl/fipsfreebl.c b/lib/freebl/fipsfreebl.c
ddf7d0
--- a/lib/freebl/fipsfreebl.c
ddf7d0
+++ b/lib/freebl/fipsfreebl.c
ddf7d0
@@ -10,18 +10,20 @@
ddf7d0
 #ifdef FREEBL_NO_DEPEND
ddf7d0
 #include "stubs.h"
ddf7d0
 #endif
ddf7d0
 
ddf7d0
 #include "blapi.h"
ddf7d0
 #include "seccomon.h" /* Required for RSA and DSA. */
ddf7d0
 #include "secerr.h"
ddf7d0
 #include "prtypes.h"
ddf7d0
+#include "secitem.h"
ddf7d0
+#include "pkcs11t.h"
ddf7d0
 
ddf7d0
-#include "ec.h" /* Required for ECDSA */
ddf7d0
+#include "ec.h" /* Required for EC */
ddf7d0
 
ddf7d0
 /*
ddf7d0
  * different platforms have different ways of calling and initial entry point
ddf7d0
  * when the dll/.so is loaded. Most platforms support either a posix pragma
ddf7d0
  * or the GCC attribute. Some platforms suppor a pre-defined name, and some
ddf7d0
  * platforms have a link line way of invoking this function.
ddf7d0
  */
ddf7d0
 
ddf7d0
@@ -283,61 +285,88 @@ freebl_fips_AES_PowerUpSelfTest(int aes_
ddf7d0
 
ddf7d0
     /* AES-CBC Known Initialization Vector (128-bits). */
ddf7d0
     static const PRUint8 aes_cbc_known_initialization_vector[] =
ddf7d0
         { "SecurityytiruceS" };
ddf7d0
 
ddf7d0
     /* AES Known Plaintext (128-bits). (blocksize is 128-bits) */
ddf7d0
     static const PRUint8 aes_known_plaintext[] = { "NetscapeepacsteN" };
ddf7d0
 
ddf7d0
+    static const PRUint8 aes_gcm_known_aad[] = { "MozillaallizoM" };
ddf7d0
+
ddf7d0
     /* AES Known Ciphertext (128-bit key). */
ddf7d0
     static const PRUint8 aes_ecb128_known_ciphertext[] = {
ddf7d0
         0x3c, 0xa5, 0x96, 0xf3, 0x34, 0x6a, 0x96, 0xc1,
ddf7d0
         0x03, 0x88, 0x16, 0x7b, 0x20, 0xbf, 0x35, 0x47
ddf7d0
     };
ddf7d0
 
ddf7d0
     static const PRUint8 aes_cbc128_known_ciphertext[] = {
ddf7d0
         0xcf, 0x15, 0x1d, 0x4f, 0x96, 0xe4, 0x4f, 0x63,
ddf7d0
         0x15, 0x54, 0x14, 0x1d, 0x4e, 0xd8, 0xd5, 0xea
ddf7d0
     };
ddf7d0
 
ddf7d0
+    static const PRUint8 aes_gcm128_known_ciphertext[] = {
ddf7d0
+        0x63, 0xf4, 0x95, 0x28, 0xe6, 0x78, 0xee, 0x6e,
ddf7d0
+        0x4f, 0xe0, 0xfc, 0x8d, 0xd7, 0xa2, 0xb1, 0xff,
ddf7d0
+        0x0c, 0x97, 0x1b, 0x0a, 0xdd, 0x97, 0x75, 0xed,
ddf7d0
+        0x8b, 0xde, 0xbf, 0x16, 0x5e, 0x57, 0x6b, 0x4f
ddf7d0
+    };
ddf7d0
+
ddf7d0
     /* AES Known Ciphertext (192-bit key). */
ddf7d0
     static const PRUint8 aes_ecb192_known_ciphertext[] = {
ddf7d0
         0xa0, 0x18, 0x62, 0xed, 0x88, 0x19, 0xcb, 0x62,
ddf7d0
         0x88, 0x1d, 0x4d, 0xfe, 0x84, 0x02, 0x89, 0x0e
ddf7d0
     };
ddf7d0
 
ddf7d0
     static const PRUint8 aes_cbc192_known_ciphertext[] = {
ddf7d0
         0x83, 0xf7, 0xa4, 0x76, 0xd1, 0x6f, 0x07, 0xbe,
ddf7d0
         0x07, 0xbc, 0x43, 0x2f, 0x6d, 0xad, 0x29, 0xe1
ddf7d0
     };
ddf7d0
 
ddf7d0
+    static const PRUint8 aes_gcm192_known_ciphertext[] = {
ddf7d0
+        0xc1, 0x0b, 0x92, 0x1d, 0x68, 0x21, 0xf4, 0x25,
ddf7d0
+        0x41, 0x61, 0x20, 0x2d, 0x59, 0x7f, 0x53, 0xde,
ddf7d0
+        0x93, 0x39, 0xab, 0x09, 0x76, 0x41, 0x57, 0x2b,
ddf7d0
+        0x90, 0x2e, 0x44, 0xbb, 0x52, 0x03, 0xe9, 0x07
ddf7d0
+    };
ddf7d0
+
ddf7d0
     /* AES Known Ciphertext (256-bit key). */
ddf7d0
     static const PRUint8 aes_ecb256_known_ciphertext[] = {
ddf7d0
         0xdb, 0xa6, 0x52, 0x01, 0x8a, 0x70, 0xae, 0x66,
ddf7d0
         0x3a, 0x99, 0xd8, 0x95, 0x7f, 0xfb, 0x01, 0x67
ddf7d0
     };
ddf7d0
 
ddf7d0
     static const PRUint8 aes_cbc256_known_ciphertext[] = {
ddf7d0
         0x37, 0xea, 0x07, 0x06, 0x31, 0x1c, 0x59, 0x27,
ddf7d0
         0xc5, 0xc5, 0x68, 0x71, 0x6e, 0x34, 0x40, 0x16
ddf7d0
     };
ddf7d0
 
ddf7d0
+    static const PRUint8 aes_gcm256_known_ciphertext[] = {
ddf7d0
+        0x5d, 0x9e, 0xd2, 0xa2, 0x74, 0x9c, 0xd9, 0x1c,
ddf7d0
+        0xd1, 0xc9, 0xee, 0x5d, 0xb6, 0xf2, 0xc9, 0xb6,
ddf7d0
+        0x79, 0x27, 0x53, 0x02, 0xa3, 0xdc, 0x22, 0xce,
ddf7d0
+        0xf4, 0xb0, 0xc1, 0x8c, 0x86, 0x51, 0xf5, 0xa1
ddf7d0
+    };
ddf7d0
+
ddf7d0
     const PRUint8 *aes_ecb_known_ciphertext =
ddf7d0
         (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_ecb128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_ecb192_known_ciphertext : aes_ecb256_known_ciphertext;
ddf7d0
 
ddf7d0
     const PRUint8 *aes_cbc_known_ciphertext =
ddf7d0
         (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_cbc128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_cbc192_known_ciphertext : aes_cbc256_known_ciphertext;
ddf7d0
 
ddf7d0
+    const PRUint8 *aes_gcm_known_ciphertext =
ddf7d0
+        (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_gcm128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_gcm192_known_ciphertext : aes_gcm256_known_ciphertext;
ddf7d0
+
ddf7d0
     /* AES variables. */
ddf7d0
-    PRUint8 aes_computed_ciphertext[FIPS_AES_ENCRYPT_LENGTH];
ddf7d0
-    PRUint8 aes_computed_plaintext[FIPS_AES_DECRYPT_LENGTH];
ddf7d0
+    PRUint8 aes_computed_ciphertext[FIPS_AES_ENCRYPT_LENGTH * 2];
ddf7d0
+    PRUint8 aes_computed_plaintext[FIPS_AES_DECRYPT_LENGTH * 2];
ddf7d0
     AESContext *aes_context;
ddf7d0
     unsigned int aes_bytes_encrypted;
ddf7d0
     unsigned int aes_bytes_decrypted;
ddf7d0
+    CK_GCM_PARAMS gcmParams;
ddf7d0
     SECStatus aes_status;
ddf7d0
 
ddf7d0
     /*check if aes_key_size is 128, 192, or 256 bits */
ddf7d0
     if ((aes_key_size != FIPS_AES_128_KEY_SIZE) &&
ddf7d0
         (aes_key_size != FIPS_AES_192_KEY_SIZE) &&
ddf7d0
         (aes_key_size != FIPS_AES_256_KEY_SIZE)) {
ddf7d0
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
ddf7d0
         return (SECFailure);
ddf7d0
@@ -450,16 +479,79 @@ freebl_fips_AES_PowerUpSelfTest(int aes_
ddf7d0
     if ((aes_status != SECSuccess) ||
ddf7d0
         (aes_bytes_decrypted != FIPS_AES_DECRYPT_LENGTH) ||
ddf7d0
         (PORT_Memcmp(aes_computed_plaintext, aes_known_plaintext,
ddf7d0
                      FIPS_AES_DECRYPT_LENGTH) != 0)) {
ddf7d0
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
ddf7d0
         return (SECFailure);
ddf7d0
     }
ddf7d0
 
ddf7d0
+    /******************************************************/
ddf7d0
+    /* AES-GCM Single-Round Known Answer Encryption Test. */
ddf7d0
+    /******************************************************/
ddf7d0
+
ddf7d0
+    gcmParams.pIv = (PRUint8 *)aes_cbc_known_initialization_vector;
ddf7d0
+    gcmParams.ulIvLen = FIPS_AES_BLOCK_SIZE;
ddf7d0
+    gcmParams.pAAD = (PRUint8 *)aes_gcm_known_aad;
ddf7d0
+    gcmParams.ulAADLen = sizeof(aes_gcm_known_aad);
ddf7d0
+    gcmParams.ulTagBits = FIPS_AES_BLOCK_SIZE * 8;
ddf7d0
+    aes_context = AES_CreateContext(aes_known_key,
ddf7d0
+                                    (PRUint8 *)&gcmParams,
ddf7d0
+                                    NSS_AES_GCM, PR_TRUE, aes_key_size,
ddf7d0
+                                    FIPS_AES_BLOCK_SIZE);
ddf7d0
+
ddf7d0
+    if (aes_context == NULL) {
ddf7d0
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
ddf7d0
+        return (SECFailure);
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    aes_status = AES_Encrypt(aes_context, aes_computed_ciphertext,
ddf7d0
+                             &aes_bytes_encrypted, FIPS_AES_ENCRYPT_LENGTH * 2,
ddf7d0
+                             aes_known_plaintext,
ddf7d0
+                             FIPS_AES_DECRYPT_LENGTH);
ddf7d0
+
ddf7d0
+    AES_DestroyContext(aes_context, PR_TRUE);
ddf7d0
+
ddf7d0
+    if ((aes_status != SECSuccess) ||
ddf7d0
+        (aes_bytes_encrypted != FIPS_AES_ENCRYPT_LENGTH * 2) ||
ddf7d0
+        (PORT_Memcmp(aes_computed_ciphertext, aes_gcm_known_ciphertext,
ddf7d0
+                     FIPS_AES_ENCRYPT_LENGTH * 2) != 0)) {
ddf7d0
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
ddf7d0
+        return (SECFailure);
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /******************************************************/
ddf7d0
+    /* AES-GCM Single-Round Known Answer Decryption Test. */
ddf7d0
+    /******************************************************/
ddf7d0
+
ddf7d0
+    aes_context = AES_CreateContext(aes_known_key,
ddf7d0
+                                    (PRUint8 *)&gcmParams,
ddf7d0
+                                    NSS_AES_GCM, PR_FALSE, aes_key_size,
ddf7d0
+                                    FIPS_AES_BLOCK_SIZE);
ddf7d0
+
ddf7d0
+    if (aes_context == NULL) {
ddf7d0
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
ddf7d0
+        return (SECFailure);
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    aes_status = AES_Decrypt(aes_context, aes_computed_plaintext,
ddf7d0
+                             &aes_bytes_decrypted, FIPS_AES_DECRYPT_LENGTH * 2,
ddf7d0
+                             aes_gcm_known_ciphertext,
ddf7d0
+                             FIPS_AES_ENCRYPT_LENGTH * 2);
ddf7d0
+
ddf7d0
+    AES_DestroyContext(aes_context, PR_TRUE);
ddf7d0
+
ddf7d0
+    if ((aes_status != SECSuccess) ||
ddf7d0
+        (aes_bytes_decrypted != FIPS_AES_DECRYPT_LENGTH) ||
ddf7d0
+        (PORT_Memcmp(aes_computed_plaintext, aes_known_plaintext,
ddf7d0
+                     FIPS_AES_DECRYPT_LENGTH) != 0)) {
ddf7d0
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
ddf7d0
+        return (SECFailure);
ddf7d0
+    }
ddf7d0
+
ddf7d0
     return (SECSuccess);
ddf7d0
 }
ddf7d0
 
ddf7d0
 /* Known Hash Message (512-bits).  Used for all hashes (incl. SHA-N [N>1]). */
ddf7d0
 static const PRUint8 known_hash_message[] = {
ddf7d0
     "The test message for the MD2, MD5, and SHA-1 hashing algorithms."
ddf7d0
 };
ddf7d0
 
ddf7d0
@@ -1089,17 +1181,17 @@ freebl_fips_ECDSA_Test(ECParams *ecparam
ddf7d0
         0x7b, 0x5a, 0x3b, 0x76, 0x4e, 0x7b, 0x7c, 0xbc,
ddf7d0
         0xf2, 0x76, 0x1c, 0x1c, 0x7f, 0xc5, 0x53, 0x2f
ddf7d0
     };
ddf7d0
 
ddf7d0
     static const PRUint8 msg[] = {
ddf7d0
         "Firefox and ThunderBird are awesome!"
ddf7d0
     };
ddf7d0
 
ddf7d0
-    unsigned char sha1[SHA1_LENGTH]; /* SHA-1 hash (160 bits) */
ddf7d0
+    unsigned char sha256[SHA256_LENGTH]; /* SHA-256 hash (256 bits) */
ddf7d0
     unsigned char sig[2 * MAX_ECKEY_LEN];
ddf7d0
     SECItem signature, digest;
ddf7d0
     ECPrivateKey *ecdsa_private_key = NULL;
ddf7d0
     ECPublicKey ecdsa_public_key;
ddf7d0
     SECStatus ecdsaStatus = SECSuccess;
ddf7d0
 
ddf7d0
     /* Generates a new EC key pair. The private key is a supplied
ddf7d0
      * random value (in seed) and the public key is the result of
ddf7d0
@@ -1131,23 +1223,23 @@ freebl_fips_ECDSA_Test(ECParams *ecparam
ddf7d0
     if (ecdsaStatus != SECSuccess) {
ddf7d0
         goto loser;
ddf7d0
     }
ddf7d0
 
ddf7d0
     /***************************************************/
ddf7d0
     /* ECDSA Single-Round Known Answer Signature Test. */
ddf7d0
     /***************************************************/
ddf7d0
 
ddf7d0
-    ecdsaStatus = SHA1_HashBuf(sha1, msg, sizeof msg);
ddf7d0
+    ecdsaStatus = SHA256_HashBuf(sha256, msg, sizeof msg);
ddf7d0
     if (ecdsaStatus != SECSuccess) {
ddf7d0
         goto loser;
ddf7d0
     }
ddf7d0
     digest.type = siBuffer;
ddf7d0
-    digest.data = sha1;
ddf7d0
-    digest.len = SHA1_LENGTH;
ddf7d0
+    digest.data = sha256;
ddf7d0
+    digest.len = SHA256_LENGTH;
ddf7d0
 
ddf7d0
     memset(sig, 0, sizeof sig);
ddf7d0
     signature.type = siBuffer;
ddf7d0
     signature.data = sig;
ddf7d0
     signature.len = sizeof sig;
ddf7d0
 
ddf7d0
     ecdsaStatus = ECDSA_SignDigestWithSeed(ecdsa_private_key, &signature,
ddf7d0
                                            &digest, ecdsa_Known_Seed, sizeof ecdsa_Known_Seed);
ddf7d0
@@ -1176,20 +1268,93 @@ loser:
ddf7d0
     if (ecdsaStatus != SECSuccess) {
ddf7d0
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
ddf7d0
         return (SECFailure);
ddf7d0
     }
ddf7d0
     return (SECSuccess);
ddf7d0
 }
ddf7d0
 
ddf7d0
 static SECStatus
ddf7d0
-freebl_fips_ECDSA_PowerUpSelfTest()
ddf7d0
+freebl_fips_ECDH_Test(ECParams *ecparams)
ddf7d0
 {
ddf7d0
 
ddf7d0
-    /* ECDSA Known curve nistp256 == ECCCurve_X9_62_PRIME_256V1 params */
ddf7d0
+    /* ECDH Known result (reused old CAVS vector)  */
ddf7d0
+    static const PRUint8 ecdh_known_pub_key_1[] = {
ddf7d0
+        EC_POINT_FORM_UNCOMPRESSED,
ddf7d0
+        /* pubX */
ddf7d0
+        0x16, 0x81, 0x32, 0x86, 0xc8, 0xe4, 0x3a, 0x1f,
ddf7d0
+        0x5d, 0xe3, 0x06, 0x22, 0x8b, 0x99, 0x14, 0x25,
ddf7d0
+        0xf7, 0x9c, 0x5b, 0x1e, 0x96, 0x84, 0x85, 0x3b,
ddf7d0
+        0x17, 0xfe, 0xf3, 0x1c, 0x0e, 0xed, 0xc4, 0xce,
ddf7d0
+        /* pubY */
ddf7d0
+        0x7a, 0x44, 0xfe, 0xbd, 0x91, 0x71, 0x7d, 0x73,
ddf7d0
+        0xd9, 0x45, 0xea, 0xae, 0x66, 0x78, 0xfa, 0x6e,
ddf7d0
+        0x46, 0xcd, 0xfa, 0x95, 0x15, 0x47, 0x62, 0x5d,
ddf7d0
+        0xbb, 0x1b, 0x9f, 0xe6, 0x39, 0xfc, 0xfd, 0x47
ddf7d0
+    };
ddf7d0
+    static const PRUint8 ecdh_known_priv_key_2[] = {
ddf7d0
+        0xb4, 0x2a, 0xe3, 0x69, 0x19, 0xec, 0xf0, 0x42,
ddf7d0
+        0x6d, 0x45, 0x8c, 0x94, 0x4a, 0x26, 0xa7, 0x5c,
ddf7d0
+        0xea, 0x9d, 0xd9, 0x0f, 0x59, 0xe0, 0x1a, 0x9d,
ddf7d0
+        0x7c, 0xb7, 0x1c, 0x04, 0x53, 0xb8, 0x98, 0x5a
ddf7d0
+    };
ddf7d0
+    static const PRUint8 ecdh_known_hash_result[] = {
ddf7d0
+        0x16, 0xf3, 0x85, 0xa2, 0x41, 0xf3, 0x7f, 0xc4,
ddf7d0
+        0x0b, 0x56, 0x47, 0xee, 0xa7, 0x74, 0xb9, 0xdb,
ddf7d0
+        0xe1, 0xfa, 0x22, 0xe9, 0x04, 0xf1, 0xb6, 0x12,
ddf7d0
+        0x4b, 0x44, 0x8a, 0xbb, 0xbc, 0x08, 0x2b, 0xa7,
ddf7d0
+    };
ddf7d0
+
ddf7d0
+    SECItem ecdh_priv_2, ecdh_pub_1;
ddf7d0
+    SECItem ZZ = { 0, 0, 0 };
ddf7d0
+    SECStatus ecdhStatus = SECSuccess;
ddf7d0
+    PRUint8 computed_hash_result[HASH_LENGTH_MAX];
ddf7d0
+
ddf7d0
+    ecdh_priv_2.data = (PRUint8 *)ecdh_known_priv_key_2;
ddf7d0
+    ecdh_priv_2.len = sizeof(ecdh_known_priv_key_2);
ddf7d0
+    ecdh_pub_1.data = (PRUint8 *)ecdh_known_pub_key_1;
ddf7d0
+    ecdh_pub_1.len = sizeof(ecdh_known_pub_key_1);
ddf7d0
+
ddf7d0
+    /* Generates a new EC key pair. The private key is a supplied
ddf7d0
+     * random value (in seed) and the public key is the result of
ddf7d0
+     * performing a scalar point multiplication of that value with
ddf7d0
+     * the curve's base point.
ddf7d0
+     */
ddf7d0
+    ecdhStatus = ECDH_Derive(&ecdh_pub_1, ecparams, &ecdh_priv_2, PR_FALSE, &ZZ;;
ddf7d0
+    if (ecdhStatus != SECSuccess) {
ddf7d0
+        goto loser;
ddf7d0
+    }
ddf7d0
+    ecdhStatus = SHA256_HashBuf(computed_hash_result, ZZ.data, ZZ.len);
ddf7d0
+    if (ecdhStatus != SECSuccess) {
ddf7d0
+        goto loser;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    if (PORT_Memcmp(computed_hash_result, ecdh_known_hash_result,
ddf7d0
+                    sizeof(ecdh_known_hash_result)) != 0) {
ddf7d0
+        ecdhStatus = SECFailure;
ddf7d0
+        goto loser;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+loser:
ddf7d0
+    if (ZZ.data) {
ddf7d0
+        SECITEM_FreeItem(&ZZ, PR_FALSE);
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    if (ecdhStatus != SECSuccess) {
ddf7d0
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
ddf7d0
+        return (SECFailure);
ddf7d0
+    }
ddf7d0
+    return (SECSuccess);
ddf7d0
+}
ddf7d0
+
ddf7d0
+static SECStatus
ddf7d0
+freebl_fips_EC_PowerUpSelfTest()
ddf7d0
+{
ddf7d0
+
ddf7d0
+    /* EC Known curve nistp256 == ECCCurve_X9_62_PRIME_256V1 params */
ddf7d0
     static const unsigned char p256_prime[] = {
ddf7d0
         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
ddf7d0
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
ddf7d0
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
ddf7d0
     };
ddf7d0
     static const unsigned char p256_a[] = {
ddf7d0
         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
ddf7d0
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
ddf7d0
@@ -1212,17 +1377,17 @@ freebl_fips_ECDSA_PowerUpSelfTest()
ddf7d0
     static const unsigned char p256_order[] = {
ddf7d0
         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
ddf7d0
         0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9,
ddf7d0
         0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51
ddf7d0
     };
ddf7d0
     static const unsigned char p256_encoding[] = {
ddf7d0
         0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
ddf7d0
     };
ddf7d0
-    static const ECParams ecdsa_known_P256_Params = {
ddf7d0
+    static const ECParams ec_known_P256_Params = {
ddf7d0
         NULL, ec_params_named,                                               /* arena, type */
ddf7d0
                                                                              /* fieldID */
ddf7d0
         { 256, ec_field_GFp,                                                 /* size and type */
ddf7d0
           { { siBuffer, (unsigned char *)p256_prime, sizeof(p256_prime) } }, /* u.prime */
ddf7d0
           0,
ddf7d0
           0,
ddf7d0
           0 },
ddf7d0
         /* curve */
ddf7d0
@@ -1245,34 +1410,39 @@ freebl_fips_ECDSA_PowerUpSelfTest()
ddf7d0
         { siBuffer, (unsigned char *)(p256_encoding) + 2, sizeof(p256_encoding) - 2 },
ddf7d0
     };
ddf7d0
 
ddf7d0
     static const PRUint8 ecdsa_known_P256_signature[] = {
ddf7d0
         0x07, 0xb1, 0xcb, 0x57, 0x20, 0xa7, 0x10, 0xd6,
ddf7d0
         0x9d, 0x37, 0x4b, 0x1c, 0xdc, 0x35, 0x90, 0xff,
ddf7d0
         0x1a, 0x2d, 0x98, 0x95, 0x1b, 0x2f, 0xeb, 0x7f,
ddf7d0
         0xbb, 0x81, 0xca, 0xc0, 0x69, 0x75, 0xea, 0xc5,
ddf7d0
-        0x59, 0x6a, 0x62, 0x49, 0x3d, 0x50, 0xc9, 0xe1,
ddf7d0
-        0x27, 0x3b, 0xff, 0x9b, 0x13, 0x66, 0x67, 0xdd,
ddf7d0
-        0x7d, 0xd1, 0x0d, 0x2d, 0x7c, 0x44, 0x04, 0x1b,
ddf7d0
-        0x16, 0x21, 0x12, 0xc5, 0xcb, 0xbd, 0x9e, 0x75
ddf7d0
+        0xa7, 0xd2, 0x20, 0xdd, 0x45, 0xf9, 0x2b, 0xdd,
ddf7d0
+        0xda, 0x98, 0x99, 0x5b, 0x1c, 0x02, 0x3a, 0x27,
ddf7d0
+        0x8b, 0x7d, 0xb6, 0xed, 0x0e, 0xe0, 0xa7, 0xac,
ddf7d0
+        0xaa, 0x36, 0x2c, 0xfa, 0x1a, 0xdf, 0x0d, 0xe1,
ddf7d0
     };
ddf7d0
 
ddf7d0
     ECParams ecparams;
ddf7d0
 
ddf7d0
     SECStatus rv;
ddf7d0
 
ddf7d0
     /* ECDSA GF(p) prime field curve test */
ddf7d0
-    ecparams = ecdsa_known_P256_Params;
ddf7d0
+    ecparams = ec_known_P256_Params;
ddf7d0
     rv = freebl_fips_ECDSA_Test(&ecparams,
ddf7d0
                                 ecdsa_known_P256_signature,
ddf7d0
                                 sizeof ecdsa_known_P256_signature);
ddf7d0
     if (rv != SECSuccess) {
ddf7d0
         return (SECFailure);
ddf7d0
     }
ddf7d0
+    /* ECDH GF(p) prime field curve test */
ddf7d0
+    rv = freebl_fips_ECDH_Test(&ecparams);
ddf7d0
+    if (rv != SECSuccess) {
ddf7d0
+        return (SECFailure);
ddf7d0
+    }
ddf7d0
 
ddf7d0
     return (SECSuccess);
ddf7d0
 }
ddf7d0
 
ddf7d0
 static SECStatus
ddf7d0
 freebl_fips_DSA_PowerUpSelfTest(void)
ddf7d0
 {
ddf7d0
     /* DSA Known P (1024-bits), Q (160-bits), and G (1024-bits) Values. */
ddf7d0
@@ -1413,16 +1583,148 @@ freebl_fips_DSA_PowerUpSelfTest(void)
ddf7d0
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
ddf7d0
         return SECFailure;
ddf7d0
     }
ddf7d0
 
ddf7d0
     return (SECSuccess);
ddf7d0
 }
ddf7d0
 
ddf7d0
 static SECStatus
ddf7d0
+freebl_fips_DH_PowerUpSelfTest(void)
ddf7d0
+{
ddf7d0
+    /* DH Known P (2048-bits) */
ddf7d0
+    static const PRUint8 dh_known_P[] = {
ddf7d0
+        0xc2, 0x79, 0xbb, 0x76, 0x32, 0x0d, 0x43, 0xfd,
ddf7d0
+        0x1b, 0x8c, 0xa2, 0x3c, 0x00, 0xdd, 0x6d, 0xef,
ddf7d0
+        0xf8, 0x1a, 0xd9, 0xc1, 0xa2, 0xf5, 0x73, 0x2b,
ddf7d0
+        0xdb, 0x1a, 0x3e, 0x84, 0x90, 0xeb, 0xe7, 0x8e,
ddf7d0
+        0x5f, 0x5c, 0x6b, 0xb6, 0x61, 0x89, 0xd1, 0x03,
ddf7d0
+        0xb0, 0x5f, 0x91, 0xe4, 0xd2, 0x82, 0x90, 0xfc,
ddf7d0
+        0x3c, 0x49, 0x69, 0x59, 0xc1, 0x51, 0x6a, 0x85,
ddf7d0
+        0x71, 0xe7, 0x5d, 0x72, 0x5a, 0x45, 0xad, 0x01,
ddf7d0
+        0x6f, 0x82, 0xae, 0xec, 0x91, 0x08, 0x2e, 0x7c,
ddf7d0
+        0x64, 0x93, 0x46, 0x1c, 0x68, 0xef, 0xc2, 0x03,
ddf7d0
+        0x28, 0x1d, 0x75, 0x3a, 0xeb, 0x9c, 0x46, 0xf0,
ddf7d0
+        0xc9, 0xdb, 0x99, 0x95, 0x13, 0x66, 0x4d, 0xd5,
ddf7d0
+        0x1a, 0x78, 0x92, 0x51, 0x89, 0x72, 0x28, 0x7f,
ddf7d0
+        0x20, 0x70, 0x41, 0x49, 0xa2, 0x86, 0xe9, 0xf9,
ddf7d0
+        0x78, 0x5f, 0x8d, 0x2e, 0x5d, 0xfa, 0xdb, 0x57,
ddf7d0
+        0xd4, 0x71, 0xdf, 0x66, 0xe3, 0x9e, 0x88, 0x70,
ddf7d0
+        0xa4, 0x21, 0x44, 0x6a, 0xc7, 0xae, 0x30, 0x2c,
ddf7d0
+        0x9c, 0x1f, 0x91, 0x57, 0xc8, 0x24, 0x34, 0x2d,
ddf7d0
+        0x7a, 0x4a, 0x43, 0xc2, 0x5f, 0xab, 0x64, 0x2e,
ddf7d0
+        0xaa, 0x28, 0x32, 0x95, 0x42, 0x7b, 0xa0, 0xcc,
ddf7d0
+        0xdf, 0xfd, 0x22, 0xc8, 0x56, 0x84, 0xc1, 0x62,
ddf7d0
+        0x15, 0xb2, 0x77, 0x86, 0x81, 0xfc, 0xa5, 0x12,
ddf7d0
+        0x3c, 0xca, 0x28, 0x17, 0x8f, 0x03, 0x16, 0x6e,
ddf7d0
+        0xb8, 0x24, 0xfa, 0x1b, 0x15, 0x02, 0xfd, 0x8b,
ddf7d0
+        0xb6, 0x0a, 0x1a, 0xf7, 0x47, 0x41, 0xc5, 0x2b,
ddf7d0
+        0x37, 0x3e, 0xa1, 0xbf, 0x68, 0xda, 0x1c, 0x55,
ddf7d0
+        0x44, 0xc3, 0xee, 0xa1, 0x63, 0x07, 0x11, 0x3b,
ddf7d0
+        0x5f, 0x00, 0x84, 0xb4, 0xc4, 0xe4, 0xa7, 0x97,
ddf7d0
+        0x29, 0xf8, 0xce, 0xab, 0xfc, 0x27, 0x3e, 0x34,
ddf7d0
+        0xe4, 0xc7, 0x81, 0x52, 0x32, 0x0e, 0x27, 0x3c,
ddf7d0
+        0xa6, 0x70, 0x3f, 0x4a, 0x54, 0xda, 0xdd, 0x60,
ddf7d0
+        0x26, 0xb3, 0x6e, 0x45, 0x26, 0x19, 0x41, 0x6f
ddf7d0
+    };
ddf7d0
+
ddf7d0
+    static const PRUint8 dh_known_Y_1[] = {
ddf7d0
+        0xb4, 0xc7, 0x85, 0xba, 0xa6, 0x98, 0xb3, 0x77,
ddf7d0
+        0x41, 0x2b, 0xd9, 0x9a, 0x72, 0x90, 0xa4, 0xac,
ddf7d0
+        0xc4, 0xf7, 0xc2, 0x23, 0x9a, 0x68, 0xe2, 0x7d,
ddf7d0
+        0x3a, 0x54, 0x45, 0x91, 0xc1, 0xd7, 0x8a, 0x17,
ddf7d0
+        0x54, 0xd3, 0x37, 0xaa, 0x0c, 0xcd, 0x0b, 0xe2,
ddf7d0
+        0xf2, 0x34, 0x0f, 0x17, 0xa8, 0x07, 0x88, 0xaf,
ddf7d0
+        0xed, 0xc1, 0x02, 0xd4, 0xdb, 0xdc, 0x0f, 0x22,
ddf7d0
+        0x51, 0x23, 0x40, 0xb9, 0x65, 0x6d, 0x39, 0xf4,
ddf7d0
+        0xe1, 0x8b, 0x57, 0x7d, 0xb6, 0xd3, 0xf2, 0x6b,
ddf7d0
+        0x02, 0xa9, 0x36, 0xf0, 0x0d, 0xe3, 0xdb, 0x9a,
ddf7d0
+        0xbf, 0x20, 0x00, 0x4d, 0xec, 0x6f, 0x68, 0x95,
ddf7d0
+        0xee, 0x59, 0x4e, 0x3c, 0xb6, 0xda, 0x7b, 0x19,
ddf7d0
+        0x08, 0x9a, 0xef, 0x61, 0x43, 0xf5, 0xfb, 0x25,
ddf7d0
+        0x70, 0x19, 0xc1, 0x5f, 0x0e, 0x0f, 0x6a, 0x63,
ddf7d0
+        0x44, 0xe9, 0xcf, 0x33, 0xce, 0x13, 0x4f, 0x34,
ddf7d0
+        0x3c, 0x94, 0x40, 0x8d, 0xf2, 0x65, 0x42, 0xef,
ddf7d0
+        0x70, 0x54, 0xdd, 0x5f, 0xc1, 0xd7, 0x0b, 0xa6,
ddf7d0
+        0x06, 0xd5, 0xa6, 0x47, 0xae, 0x2c, 0x1f, 0x5a,
ddf7d0
+        0xa6, 0xb3, 0xc1, 0x38, 0x3a, 0x3b, 0x60, 0x94,
ddf7d0
+        0xa2, 0x95, 0xab, 0xb2, 0x86, 0x82, 0xc5, 0x3b,
ddf7d0
+        0xb8, 0x6f, 0x3e, 0x55, 0x86, 0x84, 0xe0, 0x00,
ddf7d0
+        0xe5, 0xef, 0xca, 0x5c, 0xec, 0x7e, 0x38, 0x0f,
ddf7d0
+        0x82, 0xa2, 0xb1, 0xee, 0x48, 0x1b, 0x32, 0xbb,
ddf7d0
+        0x5a, 0x33, 0xa5, 0x01, 0xba, 0xca, 0xa6, 0x64,
ddf7d0
+        0x61, 0xb6, 0xe5, 0x5c, 0x0e, 0x5f, 0x2c, 0x66,
ddf7d0
+        0x0d, 0x01, 0x6a, 0x20, 0x04, 0x70, 0x68, 0x82,
ddf7d0
+        0x93, 0x29, 0x15, 0x3b, 0x7a, 0x06, 0xb2, 0x92,
ddf7d0
+        0x61, 0xcd, 0x7e, 0xa4, 0xc1, 0x15, 0x64, 0x3b,
ddf7d0
+        0x3c, 0x51, 0x10, 0x4c, 0x87, 0xa6, 0xaf, 0x07,
ddf7d0
+        0xce, 0x46, 0x82, 0x75, 0xf3, 0x90, 0xf3, 0x21,
ddf7d0
+        0x55, 0x74, 0xc2, 0xe4, 0x96, 0x7d, 0xc3, 0xe6,
ddf7d0
+        0x33, 0xa5, 0xc6, 0x51, 0xef, 0xec, 0x90, 0x08
ddf7d0
+    };
ddf7d0
+
ddf7d0
+    static const PRUint8 dh_known_x_2[] = {
ddf7d0
+        0x9e, 0x9b, 0xc3, 0x25, 0x53, 0xf9, 0xfc, 0x92,
ddf7d0
+        0xb6, 0xae, 0x54, 0x8e, 0x23, 0x4c, 0x94, 0xba,
ddf7d0
+        0x41, 0xe6, 0x29, 0x33, 0xb9, 0xdb, 0xff, 0x6d,
ddf7d0
+        0xa8, 0xb8, 0x48, 0x49, 0x66, 0x11, 0xa6, 0x13
ddf7d0
+    };
ddf7d0
+
ddf7d0
+    static const PRUint8 dh_known_hash_result[] = {
ddf7d0
+        0x93, 0xa2, 0x89, 0x1c, 0x8a, 0xc3, 0x70, 0xbf,
ddf7d0
+        0xa7, 0xdf, 0xb6, 0xd7, 0x82, 0xfb, 0x87, 0x81,
ddf7d0
+        0x09, 0x47, 0xf3, 0x9f, 0x5a, 0xbf, 0x4f, 0x3f,
ddf7d0
+        0x8e, 0x5e, 0x06, 0xca, 0x30, 0xa7, 0xaf, 0x10
ddf7d0
+    };
ddf7d0
+
ddf7d0
+    /* DH variables. */
ddf7d0
+    SECStatus dhStatus;
ddf7d0
+    SECItem dh_prime;
ddf7d0
+    SECItem dh_pub_key_1;
ddf7d0
+    SECItem dh_priv_key_2;
ddf7d0
+    SECItem ZZ = { 0, 0, 0 };
ddf7d0
+    PRUint8 computed_hash_result[HASH_LENGTH_MAX];
ddf7d0
+
ddf7d0
+    dh_prime.data = (PRUint8 *)dh_known_P;
ddf7d0
+    dh_prime.len = sizeof(dh_known_P);
ddf7d0
+    dh_pub_key_1.data = (PRUint8 *)dh_known_Y_1;
ddf7d0
+    dh_pub_key_1.len = sizeof(dh_known_Y_1);
ddf7d0
+    dh_priv_key_2.data = (PRUint8 *)dh_known_x_2;
ddf7d0
+    dh_priv_key_2.len = sizeof(dh_known_x_2);
ddf7d0
+
ddf7d0
+    /* execute the derive */
ddf7d0
+    dhStatus = DH_Derive(&dh_pub_key_1, &dh_prime, &dh_priv_key_2, &ZZ, dh_prime.len);
ddf7d0
+    if (dhStatus != SECSuccess) {
ddf7d0
+        goto loser;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    dhStatus = SHA256_HashBuf(computed_hash_result, ZZ.data, ZZ.len);
ddf7d0
+    if (dhStatus != SECSuccess) {
ddf7d0
+        goto loser;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    if (PORT_Memcmp(computed_hash_result, dh_known_hash_result,
ddf7d0
+                    sizeof(dh_known_hash_result)) != 0) {
ddf7d0
+        dhStatus = SECFailure;
ddf7d0
+        goto loser;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+loser:
ddf7d0
+    if (ZZ.data) {
ddf7d0
+        SECITEM_FreeItem(&ZZ, PR_FALSE);
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    if (dhStatus != SECSuccess) {
ddf7d0
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
ddf7d0
+        return (SECFailure);
ddf7d0
+    }
ddf7d0
+    return (SECSuccess);
ddf7d0
+}
ddf7d0
+
ddf7d0
+static SECStatus
ddf7d0
 freebl_fips_RNG_PowerUpSelfTest(void)
ddf7d0
 {
ddf7d0
     static const PRUint8 Q[] = {
ddf7d0
         0x85, 0x89, 0x9c, 0x77, 0xa3, 0x79, 0xff, 0x1a,
ddf7d0
         0x86, 0x6f, 0x2f, 0x3e, 0x2e, 0xf9, 0x8c, 0x9c,
ddf7d0
         0x9d, 0xef, 0xeb, 0xed
ddf7d0
     };
ddf7d0
     static const PRUint8 GENX[] = {
ddf7d0
@@ -1536,31 +1838,37 @@ freebl_fipsPowerUpSelfTest(unsigned int 
ddf7d0
 
ddf7d0
         /* HMAC SHA-X Power-Up SelfTest(s). */
ddf7d0
         rv = freebl_fips_HMAC_PowerUpSelfTest();
ddf7d0
 
ddf7d0
         if (rv != SECSuccess)
ddf7d0
             return rv;
ddf7d0
 
ddf7d0
         /* NOTE: RSA can only be tested in full freebl. It requires access to
ddf7d0
-     * the locking primitives */
ddf7d0
+         * the locking primitives */
ddf7d0
         /* RSA Power-Up SelfTest(s). */
ddf7d0
         rv = freebl_fips_RSA_PowerUpSelfTest();
ddf7d0
 
ddf7d0
         if (rv != SECSuccess)
ddf7d0
             return rv;
ddf7d0
 
ddf7d0
         /* DSA Power-Up SelfTest(s). */
ddf7d0
         rv = freebl_fips_DSA_PowerUpSelfTest();
ddf7d0
 
ddf7d0
         if (rv != SECSuccess)
ddf7d0
             return rv;
ddf7d0
 
ddf7d0
-        /* ECDSA Power-Up SelfTest(s). */
ddf7d0
-        rv = freebl_fips_ECDSA_PowerUpSelfTest();
ddf7d0
+        /* DH Power-Up SelfTest(s). */
ddf7d0
+        rv = freebl_fips_DH_PowerUpSelfTest();
ddf7d0
+
ddf7d0
+        if (rv != SECSuccess)
ddf7d0
+            return rv;
ddf7d0
+
ddf7d0
+        /* EC Power-Up SelfTest(s). */
ddf7d0
+        rv = freebl_fips_EC_PowerUpSelfTest();
ddf7d0
 
ddf7d0
         if (rv != SECSuccess)
ddf7d0
             return rv;
ddf7d0
     }
ddf7d0
     /* Passed Power-Up SelfTest(s). */
ddf7d0
     return (SECSuccess);
ddf7d0
 }
ddf7d0
 
ddf7d0
diff --git a/lib/freebl/intel-gcm-wrap.c b/lib/freebl/intel-gcm-wrap.c
ddf7d0
--- a/lib/freebl/intel-gcm-wrap.c
ddf7d0
+++ b/lib/freebl/intel-gcm-wrap.c
ddf7d0
@@ -138,16 +138,17 @@ intel_AES_GCM_CreateContext(void *contex
ddf7d0
 loser:
ddf7d0
     PORT_Free(gcm);
ddf7d0
     return NULL;
ddf7d0
 }
ddf7d0
 
ddf7d0
 void
ddf7d0
 intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit)
ddf7d0
 {
ddf7d0
+    PORT_Memset(gcm, 0, sizeof(intel_AES_GCMContext));
ddf7d0
     if (freeit) {
ddf7d0
         PORT_Free(gcm);
ddf7d0
     }
ddf7d0
 }
ddf7d0
 
ddf7d0
 SECStatus
ddf7d0
 intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm,
ddf7d0
                             unsigned char *outbuf,
ddf7d0
diff --git a/lib/freebl/pqg.c b/lib/freebl/pqg.c
ddf7d0
--- a/lib/freebl/pqg.c
ddf7d0
+++ b/lib/freebl/pqg.c
ddf7d0
@@ -486,21 +486,21 @@ cleanup:
ddf7d0
 **  Perform steps from  FIPS 186-3, Appendix A.1.2.1 and Appendix C.6
ddf7d0
 **
ddf7d0
 **  This generates a provable prime from two smaller prime. The resulting
ddf7d0
 **  prime p will have q0 as a multiple of p-1. q0 can be 1.
ddf7d0
 **
ddf7d0
 ** This implments steps 4 thorough 22 of FIPS 186-3 A.1.2.1 and
ddf7d0
 **                steps 16 through 34 of FIPS 186-2 C.6
ddf7d0
 */
ddf7d0
-#define MAX_ST_SEED_BITS (HASH_LENGTH_MAX * PR_BITS_PER_BYTE)
ddf7d0
 static SECStatus
ddf7d0
 makePrimefromPrimesShaweTaylor(
ddf7d0
     HASH_HashType hashtype,          /* selected Hashing algorithm */
ddf7d0
     unsigned int length,             /* input. Length of prime in bits. */
ddf7d0
+    unsigned int seedlen,            /* input seed length in bits */
ddf7d0
     mp_int *c0,                      /* seed prime */
ddf7d0
     mp_int *q,                       /* sub prime, can be 1 */
ddf7d0
     mp_int *prime,                   /* output.  */
ddf7d0
     SECItem *prime_seed,             /* input/output.  */
ddf7d0
     unsigned int *prime_gen_counter) /* input/output.  */
ddf7d0
 {
ddf7d0
     mp_int c;
ddf7d0
     mp_int c0_2;
ddf7d0
@@ -552,33 +552,32 @@ makePrimefromPrimesShaweTaylor(
ddf7d0
     */
ddf7d0
 
ddf7d0
     /* Step 4/16 iterations = ceiling(length/outlen)-1 */
ddf7d0
     iterations = (length + outlen - 1) / outlen; /* NOTE: iterations +1 */
ddf7d0
     /* Step 5/17 old_counter = prime_gen_counter */
ddf7d0
     old_counter = *prime_gen_counter;
ddf7d0
     /*
ddf7d0
     ** Comment: Generate a pseudorandom integer x in the interval
ddf7d0
-    ** [2**(lenght-1), 2**length].
ddf7d0
+    ** [2**(length-1), 2**length].
ddf7d0
     **
ddf7d0
     ** Step 6/18 x = 0
ddf7d0
     */
ddf7d0
     PORT_Memset(x, 0, sizeof(x));
ddf7d0
     /*
ddf7d0
     ** Step 7/19 for i = 0 to iterations do
ddf7d0
     **  x = x + (HASH(prime_seed + i) * 2^(i*outlen))
ddf7d0
     */
ddf7d0
     for (i = 0; i < iterations; i++) {
ddf7d0
         /* is bigger than prime_seed should get to */
ddf7d0
         CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, i,
ddf7d0
-                                       MAX_ST_SEED_BITS, &x[(iterations - i - 1) * hashlen]));
ddf7d0
+                                       seedlen, &x[(iterations - i - 1) * hashlen]));
ddf7d0
     }
ddf7d0
     /* Step 8/20 prime_seed = prime_seed + iterations + 1 */
ddf7d0
-    CHECK_SEC_OK(addToSeed(prime_seed, iterations, MAX_ST_SEED_BITS,
ddf7d0
-                           prime_seed));
ddf7d0
+    CHECK_SEC_OK(addToSeed(prime_seed, iterations, seedlen, prime_seed));
ddf7d0
     /*
ddf7d0
     ** Step 9/21 x = 2 ** (length-1) + x mod 2 ** (length-1)
ddf7d0
     **
ddf7d0
     **   This step mathematically sets the high bit and clears out
ddf7d0
     **  all the other bits higher than length. 'x' is stored
ddf7d0
     **  in the x array, MSB first. The above formula gives us an 'x'
ddf7d0
     **  which is length bytes long and has the high bit set. We also know
ddf7d0
     **  that length <= iterations*outlen since
ddf7d0
@@ -590,17 +589,17 @@ makePrimefromPrimesShaweTaylor(
ddf7d0
      * multiple of 8,*/
ddf7d0
     bit = 1 << ((length - 1) & 0x7); /* select the proper bit in the byte */
ddf7d0
     /* we need to zero out the rest of the bits in the byte above */
ddf7d0
     mask = (bit - 1);
ddf7d0
     /* now we set it */
ddf7d0
     x[offset] = (mask & x[offset]) | bit;
ddf7d0
     /*
ddf7d0
     ** Comment: Generate a candidate prime c in the interval
ddf7d0
-    ** [2**(lenght-1), 2**length].
ddf7d0
+    ** [2**(length-1), 2**length].
ddf7d0
     **
ddf7d0
     ** Step 10 t = ceiling(x/(2q(p0)))
ddf7d0
     ** Step 22 t = ceiling(x/(2(c0)))
ddf7d0
     */
ddf7d0
     CHECK_MPI_OK(mp_read_unsigned_octets(&t, &x[offset],
ddf7d0
                                          hashlen * iterations - offset)); /* t = x */
ddf7d0
     CHECK_MPI_OK(mp_mul(c0, q, &c0_2));                                   /* c0_2 is now c0*q */
ddf7d0
     CHECK_MPI_OK(mp_add(&c0_2, &c0_2, &c0_2));                            /* c0_2 is now 2*q*c0 */
ddf7d0
@@ -619,17 +618,17 @@ makePrimefromPrimesShaweTaylor(
ddf7d0
 step_23:
ddf7d0
     CHECK_MPI_OK(mp_mul(&t, &c0_2, &c);;                /* c = t*2qc0 */
ddf7d0
     CHECK_MPI_OK(mp_add_d(&c, (mp_digit)1, &c);;        /* c= 2tqc0 + 1*/
ddf7d0
     if (mpl_significant_bits(&c) > length) {            /* if c > 2**length */
ddf7d0
         CHECK_MPI_OK(mp_sub_d(&c0_2, (mp_digit)1, &t);; /* t = 2qc0-1 */
ddf7d0
         /* t = 2**(length-1) + 2qc0 -1 */
ddf7d0
         CHECK_MPI_OK(mp_add(&two_length_minus_1, &t, &t);;
ddf7d0
         /* t = floor((2**(length-1)+2qc0 -1)/2qco)
ddf7d0
-         *   = ceil(2**(lenght-2)/2qc0) */
ddf7d0
+         *   = ceil(2**(length-2)/2qc0) */
ddf7d0
         CHECK_MPI_OK(mp_div(&t, &c0_2, &t, NULL));
ddf7d0
         CHECK_MPI_OK(mp_mul(&t, &c0_2, &c);;
ddf7d0
         CHECK_MPI_OK(mp_add_d(&c, (mp_digit)1, &c);; /* c= 2tqc0 + 1*/
ddf7d0
     }
ddf7d0
     /* Step 13/25 prime_gen_counter = prime_gen_counter + 1*/
ddf7d0
     (*prime_gen_counter)++;
ddf7d0
     /*
ddf7d0
     ** Comment: Test the candidate prime c for primality; first pick an
ddf7d0
@@ -640,23 +639,21 @@ step_23:
ddf7d0
     PORT_Memset(x, 0, sizeof(x)); /* use x for a */
ddf7d0
     /*
ddf7d0
     ** Step 15/27 for i = 0 to iterations do
ddf7d0
     **  a = a + (HASH(prime_seed + i) * 2^(i*outlen))
ddf7d0
     **
ddf7d0
     ** NOTE: we reuse the x array for 'a' initially.
ddf7d0
     */
ddf7d0
     for (i = 0; i < iterations; i++) {
ddf7d0
-        /* MAX_ST_SEED_BITS is bigger than prime_seed should get to */
ddf7d0
         CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, i,
ddf7d0
-                                       MAX_ST_SEED_BITS, &x[(iterations - i - 1) * hashlen]));
ddf7d0
+                                       seedlen, &x[(iterations - i - 1) * hashlen]));
ddf7d0
     }
ddf7d0
     /* Step 16/28 prime_seed = prime_seed + iterations + 1 */
ddf7d0
-    CHECK_SEC_OK(addToSeed(prime_seed, iterations, MAX_ST_SEED_BITS,
ddf7d0
-                           prime_seed));
ddf7d0
+    CHECK_SEC_OK(addToSeed(prime_seed, iterations, seedlen, prime_seed));
ddf7d0
     /* Step 17/29 a = 2 + (a mod (c-3)). */
ddf7d0
     CHECK_MPI_OK(mp_read_unsigned_octets(&a, x, iterations * hashlen));
ddf7d0
     CHECK_MPI_OK(mp_sub_d(&c, (mp_digit)3, &z);; /* z = c -3 */
ddf7d0
     CHECK_MPI_OK(mp_mod(&a, &z, &a);;            /* a = a mod c -3 */
ddf7d0
     CHECK_MPI_OK(mp_add_d(&a, (mp_digit)2, &a);; /* a = 2 + a mod c -3 */
ddf7d0
     /*
ddf7d0
     ** Step 18 z = a**(2tq) mod p.
ddf7d0
     ** Step 30 z = a**(2t) mod c.
ddf7d0
@@ -737,16 +734,17 @@ makePrimefromSeedShaweTaylor(
ddf7d0
 {
ddf7d0
     mp_int c;
ddf7d0
     mp_int c0;
ddf7d0
     mp_int one;
ddf7d0
     SECStatus rv = SECFailure;
ddf7d0
     int hashlen = HASH_ResultLen(hashtype);
ddf7d0
     int outlen = hashlen * PR_BITS_PER_BYTE;
ddf7d0
     int offset;
ddf7d0
+    int seedlen = input_seed->len * 8; /*seedlen is in bits */
ddf7d0
     unsigned char bit, mask;
ddf7d0
     unsigned char x[HASH_LENGTH_MAX * 2];
ddf7d0
     mp_digit dummy;
ddf7d0
     mp_err err = MP_OKAY;
ddf7d0
     int i;
ddf7d0
 
ddf7d0
     MP_DIGITS(&c) = 0;
ddf7d0
     MP_DIGITS(&c0) = 0;
ddf7d0
@@ -770,30 +768,29 @@ makePrimefromSeedShaweTaylor(
ddf7d0
     */
ddf7d0
         rv = makePrimefromSeedShaweTaylor(hashtype, (length + 1) / 2 + 1,
ddf7d0
                                           input_seed, &c0, prime_seed, prime_gen_counter);
ddf7d0
         /* Step 15 if FAILURE is returned, return (FAILURE, 0, 0, 0). */
ddf7d0
         if (rv != SECSuccess) {
ddf7d0
             goto cleanup;
ddf7d0
         }
ddf7d0
         /* Steps 16-34 */
ddf7d0
-        rv = makePrimefromPrimesShaweTaylor(hashtype, length, &c0, &one,
ddf7d0
+        rv = makePrimefromPrimesShaweTaylor(hashtype, length, seedlen, &c0, &one,
ddf7d0
                                             prime, prime_seed, prime_gen_counter);
ddf7d0
         goto cleanup; /* we're done, one way or the other */
ddf7d0
     }
ddf7d0
     /* Step 3 prime_seed = input_seed */
ddf7d0
     CHECK_SEC_OK(SECITEM_CopyItem(NULL, prime_seed, input_seed));
ddf7d0
     /* Step 4 prime_gen_count = 0 */
ddf7d0
     *prime_gen_counter = 0;
ddf7d0
 
ddf7d0
 step_5:
ddf7d0
     /* Step 5 c = Hash(prime_seed) xor Hash(prime_seed+1). */
ddf7d0
     CHECK_SEC_OK(HASH_HashBuf(hashtype, x, prime_seed->data, prime_seed->len));
ddf7d0
-    CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, 1,
ddf7d0
-                                   MAX_ST_SEED_BITS, &x[hashlen]));
ddf7d0
+    CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, 1, seedlen, &x[hashlen]));
ddf7d0
     for (i = 0; i < hashlen; i++) {
ddf7d0
         x[i] = x[i] ^ x[i + hashlen];
ddf7d0
     }
ddf7d0
     /* Step 6 c = 2**length-1 + c mod 2**length-1 */
ddf7d0
     /*   This step mathematically sets the high bit and clears out
ddf7d0
     **  all the other bits higher than length. Right now c is stored
ddf7d0
     **  in the x array, MSB first. The above formula gives us a c which
ddf7d0
     **  is length bytes long and has the high bit set. We also know that
ddf7d0
@@ -812,17 +809,17 @@ step_5:
ddf7d0
     /* Step 7 c = c*floor(c/2) + 1 */
ddf7d0
     /* set the low bit. much easier to find (the end of the array) */
ddf7d0
     x[hashlen - 1] |= 1;
ddf7d0
     /* now that we've set our bits, we can create our candidate "c" */
ddf7d0
     CHECK_MPI_OK(mp_read_unsigned_octets(&c, &x[offset], hashlen - offset));
ddf7d0
     /* Step 8 prime_gen_counter = prime_gen_counter + 1 */
ddf7d0
     (*prime_gen_counter)++;
ddf7d0
     /* Step 9 prime_seed = prime_seed + 2 */
ddf7d0
-    CHECK_SEC_OK(addToSeed(prime_seed, 2, MAX_ST_SEED_BITS, prime_seed));
ddf7d0
+    CHECK_SEC_OK(addToSeed(prime_seed, 2, seedlen, prime_seed));
ddf7d0
     /* Step 10 Perform deterministic primality test on c. For example, since
ddf7d0
     ** c is small, it's primality can be tested by trial division, See
ddf7d0
     ** See Appendic C.7.
ddf7d0
     **
ddf7d0
     ** We in fact test with trial division. mpi has a built int trial divider
ddf7d0
     ** that divides all divisors up to 2^16.
ddf7d0
     */
ddf7d0
     if (prime_tab[prime_tab_size - 1] < 0xFFF1) {
ddf7d0
@@ -885,17 +882,18 @@ findQfromSeed(
ddf7d0
     unsigned int L,             /* input.  Length of p in bits. */
ddf7d0
     unsigned int N,             /* input.  Length of q in bits. */
ddf7d0
     unsigned int g,             /* input.  Length of seed in bits. */
ddf7d0
     const SECItem *seed,        /* input.  */
ddf7d0
     mp_int *Q,                  /* input. */
ddf7d0
     mp_int *Q_,                 /* output. */
ddf7d0
     unsigned int *qseed_len,    /* output */
ddf7d0
     HASH_HashType *hashtypePtr, /* output. Hash uses */
ddf7d0
-    pqgGenType *typePtr)        /* output. Generation Type used */
ddf7d0
+    pqgGenType *typePtr,        /* output. Generation Type used */
ddf7d0
+    unsigned int *qgen_counter) /* output. q_counter */
ddf7d0
 {
ddf7d0
     HASH_HashType hashtype;
ddf7d0
     SECItem firstseed = { 0, 0, 0 };
ddf7d0
     SECItem qseed = { 0, 0, 0 };
ddf7d0
     SECStatus rv;
ddf7d0
 
ddf7d0
     *qseed_len = 0; /* only set if FIPS186_3_ST_TYPE */
ddf7d0
 
ddf7d0
@@ -959,16 +957,17 @@ findQfromSeed(
ddf7d0
          * accident, someone has been tweeking with the seeds, just
ddf7d0
          * fail a this point. */
ddf7d0
                 SECITEM_FreeItem(&qseed, PR_FALSE);
ddf7d0
                 return SECFailure;
ddf7d0
             }
ddf7d0
             *qseed_len = qseed.len;
ddf7d0
             *hashtypePtr = hashtype;
ddf7d0
             *typePtr = FIPS186_3_ST_TYPE;
ddf7d0
+            *qgen_counter = count;
ddf7d0
             SECITEM_FreeItem(&qseed, PR_FALSE);
ddf7d0
             return SECSuccess;
ddf7d0
         }
ddf7d0
         SECITEM_FreeItem(&qseed, PR_FALSE);
ddf7d0
     }
ddf7d0
     /* no hash algorithms found which match seed to Q, fail */
ddf7d0
     return SECFailure;
ddf7d0
 }
ddf7d0
@@ -1383,29 +1382,33 @@ step_5:
ddf7d0
         CHECK_SEC_OK(makePrimefromSeedShaweTaylor(hashtype, N, &firstseed, &Q,
ddf7d0
                                                   &qseed, &qgen_counter));
ddf7d0
         /* Step 3. Use floor(L/2+1) and qseed to generate random prime p0
ddf7d0
      * using Appendix C.6 */
ddf7d0
         pgen_counter = 0;
ddf7d0
         CHECK_SEC_OK(makePrimefromSeedShaweTaylor(hashtype, (L + 1) / 2 + 1,
ddf7d0
                                                   &qseed, &p0, &pseed, &pgen_counter));
ddf7d0
         /* Steps 4-22 FIPS 186-3 appendix A.1.2.1.2 */
ddf7d0
-        CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L,
ddf7d0
+        CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L, seedBytes * 8,
ddf7d0
                                                     &p0, &Q, &P, &pseed, &pgen_counter));
ddf7d0
 
ddf7d0
         /* combine all the seeds */
ddf7d0
-        seed->len = firstseed.len + qseed.len + pseed.len;
ddf7d0
+        if ((qseed.len > firstseed.len) || (pseed.len > firstseed.len)) {
ddf7d0
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); /* shouldn't happen */
ddf7d0
+            goto cleanup;
ddf7d0
+        }
ddf7d0
+        seed->len = firstseed.len * 3; /*handle leading zeros in pseed and qseed*/
ddf7d0
         seed->data = PORT_ArenaZAlloc(verify->arena, seed->len);
ddf7d0
         if (seed->data == NULL) {
ddf7d0
             goto cleanup;
ddf7d0
         }
ddf7d0
         PORT_Memcpy(seed->data, firstseed.data, firstseed.len);
ddf7d0
-        PORT_Memcpy(seed->data + firstseed.len, pseed.data, pseed.len);
ddf7d0
-        PORT_Memcpy(seed->data + firstseed.len + pseed.len, qseed.data, qseed.len);
ddf7d0
-        counter = 0; /* (qgen_counter << 16) | pgen_counter; */
ddf7d0
+        PORT_Memcpy(seed->data + 2 * firstseed.len - pseed.len, pseed.data, pseed.len);
ddf7d0
+        PORT_Memcpy(seed->data + 3 * firstseed.len - qseed.len, qseed.data, qseed.len);
ddf7d0
+        counter = (qgen_counter << 16) | pgen_counter;
ddf7d0
 
ddf7d0
         /* we've generated both P and Q now, skip to generating G */
ddf7d0
         goto generate_G;
ddf7d0
     }
ddf7d0
     /* ******************************************************************
ddf7d0
     ** Step 8. (Step 4 in 186-1)
ddf7d0
     ** "Use a robust primality testing algorithm to test whether q is prime."
ddf7d0
     **
ddf7d0
@@ -1615,16 +1618,17 @@ PQG_VerifyParams(const PQGParams *params
ddf7d0
 {
ddf7d0
     SECStatus rv = SECSuccess;
ddf7d0
     unsigned int g, n, L, N, offset, outlen;
ddf7d0
     mp_int p0, P, Q, G, P_, Q_, G_, r, h;
ddf7d0
     mp_err err = MP_OKAY;
ddf7d0
     int j;
ddf7d0
     unsigned int counter_max = 0; /* handle legacy L < 1024 */
ddf7d0
     unsigned int qseed_len;
ddf7d0
+    unsigned int qgen_counter_ = 0;
ddf7d0
     SECItem pseed_ = { 0, 0, 0 };
ddf7d0
     HASH_HashType hashtype;
ddf7d0
     pqgGenType type;
ddf7d0
 
ddf7d0
 #define CHECKPARAM(cond)      \
ddf7d0
     if (!(cond)) {            \
ddf7d0
         *result = SECFailure; \
ddf7d0
         goto cleanup;         \
ddf7d0
@@ -1694,77 +1698,104 @@ PQG_VerifyParams(const PQGParams *params
ddf7d0
     CHECKPARAM(mp_cmp_d(&r, 1) == 0);
ddf7d0
     /* 5.  Q is prime */
ddf7d0
     CHECKPARAM(mpp_pprime(&Q, prime_testcount_q(L, N)) == MP_YES);
ddf7d0
     /* 6.  P is prime */
ddf7d0
     CHECKPARAM(mpp_pprime(&P, prime_testcount_p(L, N)) == MP_YES);
ddf7d0
     /* Steps 7-12 are done only if the optional PQGVerify is supplied. */
ddf7d0
     /* continue processing P */
ddf7d0
     /* 7.  counter < 4*L */
ddf7d0
-    CHECKPARAM((vfy->counter == -1) || (vfy->counter < counter_max));
ddf7d0
     /* 8.  g >= N and g < 2*L   (g is length of seed in bits) */
ddf7d0
-    g = vfy->seed.len * 8;
ddf7d0
-    CHECKPARAM(g >= N && g < counter_max / 2);
ddf7d0
+    /* step 7 and 8 are delayed until we determine which type of generation
ddf7d0
+     * was used */
ddf7d0
     /* 9.  Q generated from SEED matches Q in PQGParams. */
ddf7d0
     /* This function checks all possible hash and generation types to
ddf7d0
      * find a Q_ which matches Q. */
ddf7d0
+    g = vfy->seed.len * 8;
ddf7d0
     CHECKPARAM(findQfromSeed(L, N, g, &vfy->seed, &Q, &Q_, &qseed_len,
ddf7d0
-                             &hashtype, &type) == SECSuccess);
ddf7d0
+                             &hashtype, &type, &qgen_counter_) == SECSuccess);
ddf7d0
     CHECKPARAM(mp_cmp(&Q, &Q_) == 0);
ddf7d0
+    /* now we can do steps 7  & 8*/
ddf7d0
+    if ((type == FIPS186_1_TYPE) || (type == FIPS186_3_TYPE)) {
ddf7d0
+        CHECKPARAM((vfy->counter == -1) || (vfy->counter < counter_max));
ddf7d0
+        CHECKPARAM(g >= N && g < counter_max / 2);
ddf7d0
+    }
ddf7d0
     if (type == FIPS186_3_ST_TYPE) {
ddf7d0
         SECItem qseed = { 0, 0, 0 };
ddf7d0
         SECItem pseed = { 0, 0, 0 };
ddf7d0
         unsigned int first_seed_len;
ddf7d0
-        unsigned int pgen_counter = 0;
ddf7d0
+        unsigned int pgen_counter_ = 0;
ddf7d0
+        unsigned int qgen_counter = (vfy->counter >> 16) & 0xffff;
ddf7d0
+        unsigned int pgen_counter = (vfy->counter) & 0xffff;
ddf7d0
 
ddf7d0
         /* extract pseed and qseed from domain_parameter_seed, which is
ddf7d0
          * first_seed || pseed || qseed. qseed is first_seed + small_integer
ddf7d0
-         * pseed is qseed + small_integer. This means most of the time
ddf7d0
+         * mod the length of first_seed. pseed is qseed + small_integer mod
ddf7d0
+         * the length of first_seed. This means most of the time
ddf7d0
          * first_seed.len == qseed.len == pseed.len. Rarely qseed.len and/or
ddf7d0
-         * pseed.len will be one greater than first_seed.len, so we can
ddf7d0
-         * depend on the fact that
ddf7d0
-         *   first_seed.len = floor(domain_parameter_seed.len/3).
ddf7d0
-         * findQfromSeed returned qseed.len, so we can calculate pseed.len as
ddf7d0
-         *   pseed.len = domain_parameter_seed.len - first_seed.len - qseed.len
ddf7d0
-         * this is probably over kill, since 99.999% of the time they will all
ddf7d0
-         * be equal.
ddf7d0
-         *
ddf7d0
-         * With the lengths, we can now find the offsets;
ddf7d0
+         * pseed.len will be smaller because mpi clamps them. pqgGen
ddf7d0
+         * automatically adds the zero pad back though, so we can depend
ddf7d0
+         * domain_parameter_seed.len to be a multiple of three. We only have
ddf7d0
+         * to deal with the fact that the returned seeds from our functions
ddf7d0
+         * could be shorter.
ddf7d0
+         *   first_seed.len = domain_parameter_seed.len/3
ddf7d0
+         * We can now find the offsets;
ddf7d0
          * first_seed.data = domain_parameter_seed.data + 0
ddf7d0
          * pseed.data = domain_parameter_seed.data + first_seed.len
ddf7d0
          * qseed.data = domain_parameter_seed.data
ddf7d0
          *         + domain_paramter_seed.len - qseed.len
ddf7d0
-         *
ddf7d0
+         * We deal with pseed possibly having zero pad in the pseed check later.
ddf7d0
          */
ddf7d0
         first_seed_len = vfy->seed.len / 3;
ddf7d0
         CHECKPARAM(qseed_len < vfy->seed.len);
ddf7d0
         CHECKPARAM(first_seed_len * 8 > N - 1);
ddf7d0
-        CHECKPARAM(first_seed_len + qseed_len < vfy->seed.len);
ddf7d0
+        CHECKPARAM(first_seed_len * 8 < counter_max / 2);
ddf7d0
+        CHECKPARAM(first_seed_len >= qseed_len);
ddf7d0
         qseed.len = qseed_len;
ddf7d0
         qseed.data = vfy->seed.data + vfy->seed.len - qseed.len;
ddf7d0
-        pseed.len = vfy->seed.len - (first_seed_len + qseed_len);
ddf7d0
+        pseed.len = first_seed_len;
ddf7d0
         pseed.data = vfy->seed.data + first_seed_len;
ddf7d0
 
ddf7d0
         /*
ddf7d0
          * now complete FIPS 186-3 A.1.2.1.2. Step 1 was completed
ddf7d0
          * above in our initial checks, Step 2 was completed by
ddf7d0
          * findQfromSeed */
ddf7d0
 
ddf7d0
         /* Step 3 (status, c0, prime_seed, prime_gen_counter) =
ddf7d0
         ** (ST_Random_Prime((ceil(length/2)+1, input_seed)
ddf7d0
         */
ddf7d0
         CHECK_SEC_OK(makePrimefromSeedShaweTaylor(hashtype, (L + 1) / 2 + 1,
ddf7d0
-                                                  &qseed, &p0, &pseed_, &pgen_counter));
ddf7d0
+                                                  &qseed, &p0, &pseed_, &pgen_counter_));
ddf7d0
         /* Steps 4-22 FIPS 186-3 appendix A.1.2.1.2 */
ddf7d0
-        CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L,
ddf7d0
-                                                    &p0, &Q_, &P_, &pseed_, &pgen_counter));
ddf7d0
+        CHECK_SEC_OK(makePrimefromPrimesShaweTaylor(hashtype, L, first_seed_len * 8,
ddf7d0
+                                                    &p0, &Q_, &P_, &pseed_, &pgen_counter_));
ddf7d0
         CHECKPARAM(mp_cmp(&P, &P_) == 0);
ddf7d0
         /* make sure pseed wasn't tampered with (since it is part of
ddf7d0
          * calculating G) */
ddf7d0
+        if (pseed.len > pseed_.len) {
ddf7d0
+            /* handle the case of zero pad for pseed */
ddf7d0
+            int extra = pseed.len - pseed_.len;
ddf7d0
+            int i;
ddf7d0
+            for (i = 0; i < extra; i++) {
ddf7d0
+                if (pseed.data[i] != 0) {
ddf7d0
+                    *result = SECFailure;
ddf7d0
+                    goto cleanup;
ddf7d0
+                }
ddf7d0
+            }
ddf7d0
+            pseed.data += extra;
ddf7d0
+            pseed.len -= extra;
ddf7d0
+            /* the rest is handled in the normal compare below */
ddf7d0
+        }
ddf7d0
         CHECKPARAM(SECITEM_CompareItem(&pseed, &pseed_) == SECEqual);
ddf7d0
+        if (vfy->counter != -1) {
ddf7d0
+            CHECKPARAM(pgen_counter < counter_max);
ddf7d0
+            CHECKPARAM(qgen_counter < counter_max);
ddf7d0
+            CHECKPARAM((pgen_counter_ == pgen_counter));
ddf7d0
+            CHECKPARAM((qgen_counter_ == qgen_counter));
ddf7d0
+        }
ddf7d0
     } else if (vfy->counter == -1) {
ddf7d0
         /* If counter is set to -1, we are really only verifying G, skip
ddf7d0
          * the remainder of the checks for P */
ddf7d0
         CHECKPARAM(type != FIPS186_1_TYPE); /* we only do this for DSA2 */
ddf7d0
     } else {
ddf7d0
         /* 10. P generated from (L, counter, g, SEED, Q) matches P
ddf7d0
          * in PQGParams. */
ddf7d0
         outlen = HASH_ResultLen(hashtype) * PR_BITS_PER_BYTE;
ddf7d0
diff --git a/lib/freebl/rijndael.c b/lib/freebl/rijndael.c
ddf7d0
--- a/lib/freebl/rijndael.c
ddf7d0
+++ b/lib/freebl/rijndael.c
ddf7d0
@@ -1027,23 +1027,25 @@ AES_CreateContext(const unsigned char *k
ddf7d0
  * AES_DestroyContext
ddf7d0
  *
ddf7d0
  * Zero an AES cipher context.  If freeit is true, also free the pointer
ddf7d0
  * to the context.
ddf7d0
  */
ddf7d0
 void
ddf7d0
 AES_DestroyContext(AESContext *cx, PRBool freeit)
ddf7d0
 {
ddf7d0
+    void *mem = cx->mem;
ddf7d0
     if (cx->worker_cx && cx->destroy) {
ddf7d0
         (*cx->destroy)(cx->worker_cx, PR_TRUE);
ddf7d0
         cx->worker_cx = NULL;
ddf7d0
         cx->destroy = NULL;
ddf7d0
     }
ddf7d0
+    PORT_Memset(cx, 0, sizeof(AESContext));
ddf7d0
     if (freeit) {
ddf7d0
-        PORT_Free(cx->mem);
ddf7d0
+        PORT_Free(mem);
ddf7d0
     }
ddf7d0
 }
ddf7d0
 
ddf7d0
 /*
ddf7d0
  * AES_Encrypt
ddf7d0
  *
ddf7d0
  * Encrypt an arbitrary-length buffer.  The output buffer must already be
ddf7d0
  * allocated to at least inputLen.
ddf7d0
diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
ddf7d0
--- a/lib/softoken/pkcs11c.c
ddf7d0
+++ b/lib/softoken/pkcs11c.c
ddf7d0
@@ -4708,16 +4708,24 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
ddf7d0
                        pairwise_digest_length,
ddf7d0
                        signature,
ddf7d0
                        &signature_length);
ddf7d0
         if (crv != CKR_OK) {
ddf7d0
             PORT_Free(signature);
ddf7d0
             return crv;
ddf7d0
         }
ddf7d0
 
ddf7d0
+        /* detect trivial signing transforms */
ddf7d0
+        if (signature_length >= pairwise_digest_length) {
ddf7d0
+            if (PORT_Memcmp(known_digest, signature + (signature_length - pairwise_digest_length), pairwise_digest_length) == 0) {
ddf7d0
+                PORT_Free(signature);
ddf7d0
+                return CKR_DEVICE_ERROR;
ddf7d0
+            }
ddf7d0
+        }
ddf7d0
+
ddf7d0
         /* Verify the known hash using the public key. */
ddf7d0
         crv = NSC_VerifyInit(hSession, &mech, publicKey->handle);
ddf7d0
         if (crv != CKR_OK) {
ddf7d0
             PORT_Free(signature);
ddf7d0
             return crv;
ddf7d0
         }
ddf7d0
 
ddf7d0
         crv = NSC_Verify(hSession,
ddf7d0
@@ -7543,40 +7551,55 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
ddf7d0
             SHA512_HashBuf(key_block, (const unsigned char *)att->attrib.pValue,
ddf7d0
                            att->attrib.ulValueLen);
ddf7d0
 
ddf7d0
             crv = sftk_forceAttribute(key, CKA_VALUE, key_block, keySize);
ddf7d0
             break;
ddf7d0
 
ddf7d0
         case CKM_DH_PKCS_DERIVE: {
ddf7d0
             SECItem derived, dhPublic;
ddf7d0
-            SECItem dhPrime, dhValue;
ddf7d0
+            SECItem dhPrime, dhSubPrime, dhValue;
ddf7d0
             /* sourceKey - values for the local existing low key */
ddf7d0
             /* get prime and value attributes */
ddf7d0
             crv = sftk_Attribute2SecItem(NULL, &dhPrime, sourceKey, CKA_PRIME);
ddf7d0
-            if (crv != SECSuccess)
ddf7d0
+            if (crv != CKR_OK)
ddf7d0
                 break;
ddf7d0
             crv = sftk_Attribute2SecItem(NULL, &dhValue, sourceKey, CKA_VALUE);
ddf7d0
-            if (crv != SECSuccess) {
ddf7d0
+            if (crv != CKR_OK) {
ddf7d0
                 PORT_Free(dhPrime.data);
ddf7d0
                 break;
ddf7d0
             }
ddf7d0
 
ddf7d0
             dhPublic.data = pMechanism->pParameter;
ddf7d0
             dhPublic.len = pMechanism->ulParameterLen;
ddf7d0
 
ddf7d0
+            /* if the caller bothered to provide Q, use Q to validate.
ddf7d0
+             * the public key */
ddf7d0
+            crv = sftk_Attribute2SecItem(NULL, &dhSubPrime, sourceKey, CKA_SUBPRIME);
ddf7d0
+            if (crv == CKR_OK) {
ddf7d0
+                rv = KEA_Verify(&dhPublic, &dhPrime, &dhSubPrime);
ddf7d0
+                PORT_Free(dhSubPrime.data);
ddf7d0
+                if (rv != SECSuccess) {
ddf7d0
+                    crv = CKR_ARGUMENTS_BAD;
ddf7d0
+                    PORT_Free(dhPrime.data);
ddf7d0
+                    PORT_Free(dhValue.data);
ddf7d0
+                    break;
ddf7d0
+                }
ddf7d0
+            }
ddf7d0
+
ddf7d0
             /* calculate private value - oct */
ddf7d0
             rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize);
ddf7d0
 
ddf7d0
             PORT_Free(dhPrime.data);
ddf7d0
             PORT_Free(dhValue.data);
ddf7d0
 
ddf7d0
             if (rv == SECSuccess) {
ddf7d0
                 sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len);
ddf7d0
                 PORT_ZFree(derived.data, derived.len);
ddf7d0
+                crv = CKR_OK;
ddf7d0
             } else
ddf7d0
                 crv = CKR_HOST_MEMORY;
ddf7d0
 
ddf7d0
             break;
ddf7d0
         }
ddf7d0
 
ddf7d0
         case CKM_ECDH1_DERIVE:
ddf7d0
         case CKM_ECDH1_COFACTOR_DERIVE: {