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