# HG changeset patch
# Parent  2706b90296a4137a738f19ea81f378fc2dcce465
extend CAVS test to provide what it takes for certification

diff --git a/cmd/fipstest/dsa.sh b/cmd/fipstest/dsa.sh
--- a/cmd/fipstest/dsa.sh
+++ b/cmd/fipstest/dsa.sh
@@ -17,17 +17,17 @@ response=`echo $request | sed -e "s/req/
 echo $request $response
 fipstest dsa keypair $request > $response
 
 request=PQGGen.req
 response=`echo $request | sed -e "s/req/rsp/"`
 echo $request $response
 fipstest dsa pqggen $request > $response
 
-request=PQGVer.req
+request=PQGVer1863.req
 response=`echo $request | sed -e "s/req/rsp/"`
 echo $request $response
 fipstest dsa pqgver $request > $response
 
 request=SigGen.req
 response=`echo $request | sed -e "s/req/rsp/"`
 echo $request $response
 fipstest dsa siggen $request > $response
diff --git a/cmd/fipstest/fipstest.c b/cmd/fipstest/fipstest.c
--- a/cmd/fipstest/fipstest.c
+++ b/cmd/fipstest/fipstest.c
@@ -1,28 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <dlfcn.h>
 
 #include "secitem.h"
 #include "blapi.h"
 #include "nssutil.h"
 #include "secerr.h"
 #include "secder.h"
 #include "secdig.h"
 #include "secoid.h"
 #include "ec.h"
 #include "hasht.h"
 #include "lowkeyi.h"
 #include "softoken.h"
 
+#include "../../lib/freebl/fips.h"
+
 #if 0
 #include "../../lib/freebl/mpi/mpi.h"
 #endif
 
 #ifndef NSS_DISABLE_ECC
 extern SECStatus
 EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams);
 extern SECStatus
@@ -34,16 +37,26 @@ EC_CopyParams(PLArenaPool *arena, ECPara
 #define DECRYPT 0
 #define BYTE unsigned char
 #define DEFAULT_RSA_PUBLIC_EXPONENT   0x10001
 #define RSA_MAX_TEST_MODULUS_BITS     4096
 #define RSA_MAX_TEST_MODULUS_BYTES    RSA_MAX_TEST_MODULUS_BITS/8
 #define RSA_MAX_TEST_EXPONENT_BYTES   8
 #define PQG_TEST_SEED_BYTES           20
 
+/* Function pointers for dynamically loaded functions */
+void *(*FREEBL_GetGlobalVar_p) (int which, void *data);
+SECStatus (*FREEBL_Test_PQG_ParamGenV3_p) (unsigned int L, unsigned int N, unsigned int seedBytes,
+                                           PQGParams **pParams, PQGVerify **pVfy,
+                                           int shanum, int *pgen_counter, int *qgen_counter,
+                                           SECItem *firstseed, SECItem *pseed, SECItem *qseed);
+SECStatus (*FREEBL_Test_PQG_GenerateG_p) (unsigned int L, unsigned int N, unsigned int seedBytes,
+                                          PQGParams **pParams, PQGVerify **pVfy,
+                                          int shanum, const SECItem *P, const SECItem *Q);
+
 SECStatus
 hex_to_byteval(const char *c2, unsigned char *byteval)
 {
     int i;
     unsigned char offset;
     *byteval = 0;
     for (i=0; i<2; i++) {
 	if (c2[i] >= '0' && c2[i] <= '9') {
@@ -93,16 +106,34 @@ to_hex_str_cap(char *str, const unsigned
 {
     unsigned int i;
     for (i=0; i<len; i++) {
 	byteval_to_hex(buf[i], &str[2*i], 'A');
     }
     str[2*len] = '\0';
 }
 
+void
+to_hex_str_pad (char *str, const unsigned char *buf, unsigned int len, unsigned int padlen)
+{
+    unsigned int i, j;
+
+    for (j = 0; len < padlen; padlen--)
+    {
+        str [j++] = '0';
+        str [j++] = '0';
+    }
+
+    for (i=0; i<len; i++, j += 2) {
+	byteval_to_hex(buf[i], &str[j], 'a');
+    }
+
+    str[j] = '\0';
+}
+
 /*
  * Convert a string of hex digits (str) to an array (buf) of len bytes.
  * Return PR_TRUE if the hex string can fit in the byte array.  Return
  * PR_FALSE if the hex string is empty or is too long.
  */
 PRBool
 from_hex_str(unsigned char *buf, unsigned int len, const char *str)
 {
@@ -147,16 +178,181 @@ from_hex_str(unsigned char *buf, unsigne
 	} else {
 	    hex_to_byteval(&str[j], &buf[i]);
 	    j += 2;
 	}
     }
     return PR_TRUE;
 }
 
+/*
+ * Convert a string of hex digits (str) to an array (buf) of maxlen bytes.
+ * Return length of resulting output in buf, or 0 on error.
+ */
+int
+from_hex_str_varlen (unsigned char *buf, unsigned int maxlen, const char *str)
+{
+    unsigned int nxdigit;  /* number of hex digits in str */
+    unsigned int i;  /* index into buf */
+    unsigned int j;  /* index into str */
+
+    /* count the hex digits */
+    nxdigit = 0;
+    for (nxdigit = 0; isxdigit (str [nxdigit]); nxdigit++) {
+	/* empty body */
+    }
+    if (nxdigit == 0) {
+	return 0;
+    }
+
+    for (i = 0, j = 0; j < nxdigit; i++) {
+	if ((nxdigit - j) % 2 == 1) {
+           char tmp [2];
+           tmp [0] = '0';
+           tmp [1] = str [j];
+           hex_to_byteval (tmp, &buf [i]);
+           j++;
+	} else {
+	    hex_to_byteval (&str [j], &buf [i]);
+	    j += 2;
+	}
+    }
+    return i;
+}
+
+/*
+ * HASH_ functions are available to full NSS apps and internally inside
+ * freebl, but not exported to users of freebl. Create short stubs to
+ * replace the functionality for fipstest.
+ */
+SECStatus
+fips_hashBuf(HASH_HashType type, unsigned char *hashBuf, 
+					unsigned char *msg, int len)
+{
+    SECStatus rv = SECFailure;
+
+    switch (type) {
+    case HASH_AlgSHA1:
+	rv = SHA1_HashBuf(hashBuf, msg, len);
+	break;
+    case HASH_AlgSHA224:
+	rv = SHA224_HashBuf(hashBuf, msg, len);
+	break;
+    case HASH_AlgSHA256:
+	rv = SHA256_HashBuf(hashBuf, msg, len);
+	break;
+    case HASH_AlgSHA384:
+	rv = SHA384_HashBuf(hashBuf, msg, len);
+	break;
+    case HASH_AlgSHA512:
+	rv = SHA512_HashBuf(hashBuf, msg, len);
+	break;
+    default:
+	break;
+    }
+    return rv;
+}
+
+int
+fips_hashLen(HASH_HashType type)
+{
+    int len = 0;
+
+    switch (type) {
+    case HASH_AlgSHA1:
+	len = SHA1_LENGTH;
+	break;
+    case HASH_AlgSHA224:
+	len = SHA224_LENGTH;
+	break;
+    case HASH_AlgSHA256:
+	len = SHA256_LENGTH;
+	break;
+    case HASH_AlgSHA384:
+	len = SHA384_LENGTH;
+	break;
+    case HASH_AlgSHA512:
+	len = SHA512_LENGTH;
+	break;
+    default:
+	break;
+    }
+    return len;
+}
+
+SECOidTag
+fips_hashOid(HASH_HashType type)
+{
+    SECOidTag oid = SEC_OID_UNKNOWN;
+
+    switch (type) {
+    case HASH_AlgSHA1:
+	oid = SEC_OID_SHA1;
+	break;
+    case HASH_AlgSHA224:
+	oid = SEC_OID_SHA224;
+	break;
+    case HASH_AlgSHA256:
+	oid = SEC_OID_SHA256;
+	break;
+    case HASH_AlgSHA384:
+	oid = SEC_OID_SHA384;
+	break;
+    case HASH_AlgSHA512:
+	oid = SEC_OID_SHA512;
+	break;
+    default:
+	break;
+    }
+    return oid;
+}
+
+HASH_HashType
+sha_get_hashType(int hashbits)
+{
+    HASH_HashType hashType = HASH_AlgNULL;
+
+    switch (hashbits) {
+    case 1:
+    case (SHA1_LENGTH*PR_BITS_PER_BYTE):
+	hashType = HASH_AlgSHA1;
+	break;
+    case (SHA224_LENGTH*PR_BITS_PER_BYTE):
+	hashType = HASH_AlgSHA224;
+	break;
+    case (SHA256_LENGTH*PR_BITS_PER_BYTE):
+	hashType = HASH_AlgSHA256;
+	break;
+    case (SHA384_LENGTH*PR_BITS_PER_BYTE):
+	hashType = HASH_AlgSHA384;
+	break;
+    case (SHA512_LENGTH*PR_BITS_PER_BYTE):
+	hashType = HASH_AlgSHA512;
+	break;
+    default:
+	break;
+    }
+    return hashType;
+}
+
+/*
+ * Calculate the SHA Message Digest 
+ *
+ * MD = Message digest 
+ * MDLen = length of Message Digest and SHA_Type
+ * msg = message to digest 
+ * msgLen = length of message to digest
+ */
+SECStatus sha_calcMD(unsigned char *MD, unsigned int MDLen, unsigned char *msg, unsigned int msgLen) 
+{    
+    HASH_HashType  hashType = sha_get_hashType(MDLen*PR_BITS_PER_BYTE);
+
+    return fips_hashBuf(hashType, MD, msg, msgLen);
+}
+
 SECStatus
 tdea_encrypt_buf(
     int mode,
     const unsigned char *key, 
     const unsigned char *iv,
     unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
     const unsigned char *input, unsigned int inputlen)
 {
@@ -2001,22 +2197,22 @@ ecdsa_keypair_test(char *reqfn)
     int i;
     unsigned int len;
 
     ecdsareq = fopen(reqfn, "r");
     ecdsaresp = stdout;
     strcpy(curve, "nist");
     while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
 	/* a comment or blank line */
-	if (buf[0] == '#' || buf[0] == '\n') {
+	if (buf[0] == '#' || buf[0] == '\n' || buf [0] == '\r') {
 	    fputs(buf, ecdsaresp);
 	    continue;
 	}
 	/* [X-ddd] */
-	if (buf[0] == '[') {
+	if (buf[0] == '[' && buf [1] != '\0' && buf [2] == '-') {
 	    const char *src;
 	    char *dst;
 	    SECItem *encodedparams;
 
 	    src = &buf[1];
 	    dst = &curve[4];
 	    *dst++ = tolower(*src);
 	    src += 2;  /* skip the hyphen */
@@ -2030,16 +2226,21 @@ ecdsa_keypair_test(char *reqfn)
 	    }
 	    if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
 		goto loser;
 	    }
 	    SECITEM_FreeItem(encodedparams, PR_TRUE);
 	    fputs(buf, ecdsaresp);
 	    continue;
 	}
+        /* [...] */
+        if (buf [0] == '[') {
+	     fputs(buf, ecdsaresp);
+            continue;
+        }
 	/* N = x */
 	if (buf[0] == 'N') {
 	    if (sscanf(buf, "N = %d", &N) != 1) {
 		goto loser;
 	    }
 	    for (i = 0; i < N; i++) {
 		ECPrivateKey *ecpriv;
 
@@ -2216,20 +2417,23 @@ ecdsa_siggen_test(char *reqfn)
                          * needs to be large enough to hold the longest
                          * line "Msg = <256 hex digits>\n".
                          */
     FILE *ecdsareq;     /* input stream from the REQUEST file */
     FILE *ecdsaresp;    /* output stream to the RESPONSE file */
     char curve[16];     /* "nistxddd" */
     ECParams *ecparams = NULL;
     int i, j;
+    char c;
+    int curvenum;
+    int shanum;
     unsigned int len;
     unsigned char msg[512];  /* message to be signed (<= 128 bytes) */
     unsigned int msglen;
-    unsigned char sha1[20];  /* SHA-1 hash (160 bits) */
+    unsigned char md[SHA512_LENGTH];
     unsigned char sig[2*MAX_ECKEY_LEN];
     SECItem signature, digest;
 
     ecdsareq = fopen(reqfn, "r");
     ecdsaresp = stdout;
     strcpy(curve, "nist");
     while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
 	/* a comment or blank line */
@@ -2238,16 +2442,19 @@ ecdsa_siggen_test(char *reqfn)
 	    continue;
 	}
 	/* [X-ddd] */
 	if (buf[0] == '[') {
 	    const char *src;
 	    char *dst;
 	    SECItem *encodedparams;
 
+            if (sscanf (buf, "[%c-%d,SHA-%d]", &c, &curvenum, &shanum) != 3)
+                goto loser;
+
 	    src = &buf[1];
 	    dst = &curve[4];
 	    *dst++ = tolower(*src);
 	    src += 2;  /* skip the hyphen */
 	    *dst++ = *src++;
 	    *dst++ = *src++;
 	    *dst++ = *src++;
 	    *dst = '\0';
@@ -2273,17 +2480,17 @@ ecdsa_siggen_test(char *reqfn)
 	    i = 3;
 	    while (isspace(buf[i]) || buf[i] == '=') {
 		i++;
 	    }
 	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
 		hex_to_byteval(&buf[i], &msg[j]);
 	    }
 	    msglen = j;
-	    if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) {
+	    if (fips_hashBuf(sha_get_hashType(shanum), md, msg, msglen) != SECSuccess) {
 		goto loser;
 	    }
 	    fputs(buf, ecdsaresp);
 
 	    if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) {
 		goto loser;
 	    }
 	    if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue)
@@ -2303,18 +2510,18 @@ ecdsa_siggen_test(char *reqfn)
 	    fputs(buf, ecdsaresp);
 	    fputc('\n', ecdsaresp);
 	    fputs("Qy = ", ecdsaresp);
 	    to_hex_str(buf, &ecpriv->publicValue.data[1+len], len);
 	    fputs(buf, ecdsaresp);
 	    fputc('\n', ecdsaresp);
 
 	    digest.type = siBuffer;
-	    digest.data = sha1;
-	    digest.len = sizeof sha1;
+	    digest.data = md;
+	    digest.len = fips_hashLen (sha_get_hashType (shanum));
 	    signature.type = siBuffer;
 	    signature.data = sig;
 	    signature.len = sizeof sig;
 	    if (ECDSA_SignDigest(ecpriv, &signature, &digest) != SECSuccess) {
 		goto loser;
 	    }
 	    len = signature.len;
 	    if (len%2 != 0) {
@@ -2355,21 +2562,24 @@ ecdsa_sigver_test(char *reqfn)
                          * needs to be large enough to hold the longest
                          * line "Msg = <256 hex digits>\n".
                          */
     FILE *ecdsareq;     /* input stream from the REQUEST file */
     FILE *ecdsaresp;    /* output stream to the RESPONSE file */
     char curve[16];     /* "nistxddd" */
     ECPublicKey ecpub;
     unsigned int i, j;
+    char c;
+    int curvenum;
+    int shanum;
     unsigned int flen;  /* length in bytes of the field size */
     unsigned int olen;  /* length in bytes of the base point order */
     unsigned char msg[512];  /* message that was signed (<= 128 bytes) */
     unsigned int msglen;
-    unsigned char sha1[20];  /* SHA-1 hash (160 bits) */
+    unsigned char md[SHA512_LENGTH];
     unsigned char sig[2*MAX_ECKEY_LEN];
     SECItem signature, digest;
     PRBool keyvalid = PR_TRUE;
     PRBool sigvalid = PR_TRUE;
 
     ecdsareq = fopen(reqfn, "r");
     ecdsaresp = stdout;
     ecpub.ecParams.arena = NULL;
@@ -2382,16 +2592,19 @@ ecdsa_sigver_test(char *reqfn)
 	}
 	/* [X-ddd] */
 	if (buf[0] == '[') {
 	    const char *src;
 	    char *dst;
 	    SECItem *encodedparams;
 	    ECParams *ecparams;
 
+	    if (sscanf (buf, "[%c-%d,SHA-%d]", &c, &curvenum, &shanum) != 3)
+		goto loser;
+
 	    src = &buf[1];
 	    dst = &curve[4];
 	    *dst++ = tolower(*src);
 	    src += 2;  /* skip the hyphen */
 	    *dst++ = *src++;
 	    *dst++ = *src++;
 	    *dst++ = *src++;
 	    *dst = '\0';
@@ -2437,24 +2650,24 @@ ecdsa_sigver_test(char *reqfn)
 	    i = 3;
 	    while (isspace(buf[i]) || buf[i] == '=') {
 		i++;
 	    }
 	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
 		hex_to_byteval(&buf[i], &msg[j]);
 	    }
 	    msglen = j;
-	    if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) {
+	    if (fips_hashBuf(sha_get_hashType(shanum), md, msg, msglen) != SECSuccess) {
 		goto loser;
 	    }
 	    fputs(buf, ecdsaresp);
 
 	    digest.type = siBuffer;
-	    digest.data = sha1;
-	    digest.len = sizeof sha1;
+	    digest.data = md;
+	    digest.len = fips_hashLen (sha_get_hashType (shanum));
 
 	    continue;
 	}
 	/* Qx = ... */
 	if (strncmp(buf, "Qx", 2) == 0) {
 	    fputs(buf, ecdsaresp);
 	    i = 2;
 	    while (isspace(buf[i]) || buf[i] == '=') {
@@ -2603,19 +2816,19 @@ drbg(char *reqfn)
     unsigned char *nonce =  NULL;
     int nonceLen = 0;
     unsigned char *personalizationString =  NULL;
     int personalizationStringLen = 0;
     unsigned char *additionalInput =  NULL;
     int additionalInputLen = 0;
     unsigned char *entropyInput = NULL;
     int entropyInputLen = 0;
-    unsigned char predictedreturn_bytes[SHA256_LENGTH];
-    unsigned char return_bytes[SHA256_LENGTH];
-    int return_bytes_len = SHA256_LENGTH;
+    unsigned char *predictedreturn_bytes = NULL;
+    unsigned char *return_bytes = NULL;
+    int return_bytes_len = 0;
     enum { NONE, INSTANTIATE, GENERATE, RESEED, RESULT } command =
     NONE;
     PRBool genResult = PR_FALSE;
     SECStatus rv;
     
     rngreq = fopen(reqfn, "r");
     rngresp = stdout;
     while (fgets(buf, sizeof buf, rngreq) != NULL) {
@@ -2804,16 +3017,41 @@ drbg(char *reqfn)
 	    additionalInputLen = additionalInputLen/8;
             if (additionalInputLen > 0) {
                 additionalInput = PORT_Alloc(additionalInputLen);
             }
             fputs(buf, rngresp);
             continue;
         }
         
+        if (strncmp(buf, "[ReturnedBitsLen", 16)  == 0) {
+            if (return_bytes) {
+                PORT_ZFree(return_bytes, return_bytes_len);
+                return_bytes = NULL;
+            }
+
+            if (predictedreturn_bytes) {
+                PORT_ZFree(predictedreturn_bytes, return_bytes_len);
+                predictedreturn_bytes = NULL;
+            }
+
+            return_bytes_len = 0;
+
+            if (sscanf(buf, "[ReturnedBitsLen = %d]", &return_bytes_len) != 1) {
+                goto loser;
+            }
+	    return_bytes_len = return_bytes_len/8;
+            if (return_bytes_len > 0) {
+                return_bytes = PORT_Alloc(return_bytes_len);
+                predictedreturn_bytes = PORT_Alloc(return_bytes_len);
+            }
+            fputs(buf, rngresp);
+            continue;
+        }
+
         if (strncmp(buf, "COUNT", 5) == 0) {
             /* zeroize the variables for the test with this data set */
             if (entropyInput) {
                 memset(entropyInput, 0, entropyInputLen);
             }
             if (nonce) {
                 memset(nonce, 0, nonceLen);        
             }
@@ -2954,17 +3192,17 @@ drbg(char *reqfn)
                 to_hex_str(buf, predictedreturn_bytes, 
                            return_bytes_len);
                 fputs(buf, stderr);
                 fputs("\n   actual  = ", stderr);
                 fputs(buf2, stderr);
                 fputc('\n', stderr);
 		}
             }
-            memset(predictedreturn_bytes, 0 , sizeof predictedreturn_bytes);
+            memset(predictedreturn_bytes, 0, return_bytes_len);
 
             continue;
         }
     }
 loser:
     fclose(rngreq);
 }
 
@@ -3213,146 +3451,16 @@ rng_mct(char *reqfn)
 	    continue;
 	}
     }
 loser:
     fclose(rngreq);
 }
 
 /*
- * HASH_ functions are available to full NSS apps and internally inside
- * freebl, but not exported to users of freebl. Create short stubs to
- * replace the functionality for fipstest.
- */
-SECStatus
-fips_hashBuf(HASH_HashType type, unsigned char *hashBuf, 
-					unsigned char *msg, int len)
-{
-    SECStatus rv = SECFailure;
-
-    switch (type) {
-    case HASH_AlgSHA1:
-	rv = SHA1_HashBuf(hashBuf, msg, len);
-	break;
-    case HASH_AlgSHA224:
-	rv = SHA224_HashBuf(hashBuf, msg, len);
-	break;
-    case HASH_AlgSHA256:
-	rv = SHA256_HashBuf(hashBuf, msg, len);
-	break;
-    case HASH_AlgSHA384:
-	rv = SHA384_HashBuf(hashBuf, msg, len);
-	break;
-    case HASH_AlgSHA512:
-	rv = SHA512_HashBuf(hashBuf, msg, len);
-	break;
-    default:
-	break;
-    }
-    return rv;
-}
-
-int
-fips_hashLen(HASH_HashType type)
-{
-    int len = 0;
-
-    switch (type) {
-    case HASH_AlgSHA1:
-	len = SHA1_LENGTH;
-	break;
-    case HASH_AlgSHA224:
-	len = SHA224_LENGTH;
-	break;
-    case HASH_AlgSHA256:
-	len = SHA256_LENGTH;
-	break;
-    case HASH_AlgSHA384:
-	len = SHA384_LENGTH;
-	break;
-    case HASH_AlgSHA512:
-	len = SHA512_LENGTH;
-	break;
-    default:
-	break;
-    }
-    return len;
-}
-
-SECOidTag
-fips_hashOid(HASH_HashType type)
-{
-    SECOidTag oid = SEC_OID_UNKNOWN;
-
-    switch (type) {
-    case HASH_AlgSHA1:
-	oid = SEC_OID_SHA1;
-	break;
-    case HASH_AlgSHA224:
-	oid = SEC_OID_SHA224;
-	break;
-    case HASH_AlgSHA256:
-	oid = SEC_OID_SHA256;
-	break;
-    case HASH_AlgSHA384:
-	oid = SEC_OID_SHA384;
-	break;
-    case HASH_AlgSHA512:
-	oid = SEC_OID_SHA512;
-	break;
-    default:
-	break;
-    }
-    return oid;
-}
-
-HASH_HashType
-sha_get_hashType(int hashbits)
-{
-    HASH_HashType hashType = HASH_AlgNULL;
-
-    switch (hashbits) {
-    case 1:
-    case (SHA1_LENGTH*PR_BITS_PER_BYTE):
-	hashType = HASH_AlgSHA1;
-	break;
-    case (SHA224_LENGTH*PR_BITS_PER_BYTE):
-	hashType = HASH_AlgSHA224;
-	break;
-    case (SHA256_LENGTH*PR_BITS_PER_BYTE):
-	hashType = HASH_AlgSHA256;
-	break;
-    case (SHA384_LENGTH*PR_BITS_PER_BYTE):
-	hashType = HASH_AlgSHA384;
-	break;
-    case (SHA512_LENGTH*PR_BITS_PER_BYTE):
-	hashType = HASH_AlgSHA512;
-	break;
-    default:
-	break;
-    }
-    return hashType;
-}
-
-/*
- * Calculate the SHA Message Digest 
- *
- * MD = Message digest 
- * MDLen = length of Message Digest and SHA_Type
- * msg = message to digest 
- * msgLen = length of message to digest
- */
-SECStatus sha_calcMD(unsigned char *MD, unsigned int MDLen, unsigned char *msg, unsigned int msgLen) 
-{    
-    HASH_HashType  hashType = sha_get_hashType(MDLen*PR_BITS_PER_BYTE);
-
-    return fips_hashBuf(hashType, MD, msg, msgLen);
-}
-
-/*
  * Perform the SHA Monte Carlo Test
  *
  * MDLen = length of Message Digest and SHA_Type
  * seed = input seed value
  * resp = is the output response file. 
  */
 SECStatus sha_mct_test(unsigned int MDLen, unsigned char *seed, FILE *resp) 
 {
@@ -3414,17 +3522,17 @@ SECStatus sha_mct_test(unsigned int MDLe
  * The output RESPONSE file is written to stdout.
  */
 void sha_test(char *reqfn) 
 {
     unsigned int i, j;
     unsigned int MDlen;   /* the length of the Message Digest in Bytes  */
     unsigned int msgLen;  /* the length of the input Message in Bytes */
     unsigned char *msg = NULL; /* holds the message to digest.*/
-    size_t bufSize = 25608; /*MAX buffer size */
+    size_t bufSize = 102400; /*MAX buffer size */
     char *buf = NULL;      /* holds one line from the input REQUEST file.*/
     unsigned char seed[HASH_LENGTH_MAX];   /* max size of seed 64 bytes */
     unsigned char MD[HASH_LENGTH_MAX];     /* message digest */
 
     FILE *req = NULL;  /* input stream from the REQUEST file */
     FILE *resp;        /* output stream to the RESPONSE file */
 
     buf = PORT_ZAlloc(bufSize);
@@ -3721,17 +3829,17 @@ void hmac_test(char *reqfn)
                 hex_to_byteval(&buf[i], &msg[j]);
             }
            fputs(buf, resp);
            /* calculate the HMAC and output */ 
            if (hmac_calc(HMAC, HMACLen, key, keyLen,   
                          msg, msgLen, hash_alg) != SECSuccess) {
                goto loser;
            }
-           fputs("MAC = ", resp);
+           fputs("Mac = ", resp);
            to_hex_str(buf, HMAC, TLen);
            fputs(buf, resp);
            fputc('\n', resp);
            continue;
         }
     }
 loser:
     if (req) {
@@ -3868,16 +3976,17 @@ loser:
 
 /*
  * pqg generation type
  */
 typedef enum {
     FIPS186_1,/* Generate/Verify P,Q & G  according to FIPS 186-1 */
     A_1_1_2, /* Generate Probable P & Q */
     A_1_1_3, /* Verify Probable P & Q */
+    A_1_2_1, /* Generate Provable P & Q */
     A_1_2_2, /* Verify Provable P & Q */
     A_2_1,   /* Generate Unverifiable G */
     A_2_2,   /* Assure Unverifiable G */
     A_2_3,   /* Generate Verifiable G */
     A_2_4    /* Verify Verifiable G */
 } dsa_pqg_type;
 
 /*
@@ -3906,17 +4015,17 @@ dsa_pqgver_test(char *reqfn)
 
     dsareq = fopen(reqfn, "r");
     dsaresp = stdout;
     memset(&pqg, 0, sizeof(pqg));
     memset(&vfy, 0, sizeof(vfy));
 
     while (fgets(buf, sizeof buf, dsareq) != NULL) {
         /* a comment or blank line */
-        if (buf[0] == '#' || buf[0] == '\n') {
+        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
             fputs(buf, dsaresp);
             continue;
         }
 
         /* [A.xxxxx ] */
         if (buf[0] == '['  && buf[1] == 'A') {
 
 	    if (strncmp(&buf[1],"A.1.1.3",7) == 0) {
@@ -4119,17 +4228,16 @@ dsa_pqgver_test(char *reqfn)
                 if (rv != SECSuccess) {
                     goto loser;
                 }
                 if (result == SECSuccess) {
                     fprintf(dsaresp, "Result = P\n");
                 } else {
                     fprintf(dsaresp, "Result = F\n");
                 }
-                fprintf(dsaresp, "\n");
             }
             continue;
         }
 	if (strncmp(buf,"pgen_counter", 12) == 0) {
             if (sscanf(buf, "pgen_counter = %u", &vfy.counter) != 1) {
                 goto loser;
             }	
             fputs(buf, dsaresp);
@@ -4144,17 +4252,16 @@ dsa_pqgver_test(char *reqfn)
                 if (rv != SECSuccess) {
                     goto loser;
                 }
                 if (result == SECSuccess) {
                     fprintf(dsaresp, "Result = P\n");
                 } else {
                     fprintf(dsaresp, "Result = F\n");
                 }
-                fprintf(dsaresp, "\n");
             } 
 	    continue;
 	}
         /* H = ... */
         if (buf[0] == 'H') {
             SECStatus rv, result = SECFailure;
 
             i = 1;
@@ -4182,17 +4289,16 @@ dsa_pqgver_test(char *reqfn)
             if (rv != SECSuccess) {
                 goto loser;
             }
             if (result == SECSuccess) {
                 fprintf(dsaresp, "Result = P\n");
             } else {
                 fprintf(dsaresp, "Result = F\n");
             }
-            fprintf(dsaresp, "\n");
             continue;
         }
     }
 loser:
     fclose(dsareq);
     if (pqg.prime.data) { /* P */
         SECITEM_ZfreeItem(&pqg.prime, PR_FALSE);
     }
@@ -4226,61 +4332,63 @@ dsa_pqggen_test(char *reqfn)
                          * 800 to hold seed = (384 public key (x2 for HEX)
                          */
     FILE *dsareq;     /* input stream from the REQUEST file */
     FILE *dsaresp;    /* output stream to the RESPONSE file */
     int count;            /* number of times to generate parameters */
     int N;
     int L;
     int i;
+    int shanum = 0;
     unsigned int j;
     PQGParams *pqg = NULL;
     PQGVerify *vfy = NULL;
+    SECItem P, Q;
     unsigned int keySizeIndex;
     dsa_pqg_type type = FIPS186_1;
 
     dsareq = fopen(reqfn, "r");
     dsaresp = stdout;
     while (fgets(buf, sizeof buf, dsareq) != NULL) {
         /* a comment or blank line */
-        if (buf[0] == '#' || buf[0] == '\n') {
+        if (buf[0] == '#' || buf[0] == '\n' || buf [0] == '\r') {
             fputs(buf, dsaresp);
             continue;
         }
 
         /* [A.xxxxx ] */
         if (buf[0] == '['  && buf[1] == 'A') {
 	    if (strncmp(&buf[1],"A.1.1.2",7) == 0) {
 		type = A_1_1_2;
 	    } else if (strncmp(&buf[1],"A.2.1",5) == 0) {
-		fprintf(stderr, "NSS only Generates G with P&Q\n");
-		exit(1);
+                type = A_2_1;
 	    } else if (strncmp(&buf[1],"A.2.3",5) == 0) {
 		fprintf(stderr, "NSS only Generates G with P&Q\n");
 		exit(1);
 	    } else if (strncmp(&buf[1],"A.1.2.1",7) == 0) {
-		fprintf(stderr, "NSS does not support Shawe-Taylor Primes\n");
-		exit(1);
+                type = A_1_2_1;
 	    } else {
 		fprintf(stderr, "Unknown dsa ver test %s\n", &buf[1]);
 		exit(1);
 	    }
             fputs(buf, dsaresp);
             continue;
         }
 
         /* [Mod = ... ] */
         if (buf[0] == '[') {
+            shanum = 0;
 
 	    if (type == FIPS186_1) {
                 N=160;
                 if (sscanf(buf, "[mod = %d]", &L) != 1) {
                     goto loser;
 		}
-	    } else if (sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) {
+	    } else if (sscanf (buf, "[mod = L=%d, N=%d, SHA-%d", &L, &N, &shanum) != 3 &&
+                       sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) {
 		goto loser;
             }
 
             fputs(buf, dsaresp);
             fputc('\n', dsaresp);
 
 	    if (type == FIPS186_1) {
                 /************************************************************
@@ -4292,71 +4400,151 @@ dsa_pqggen_test(char *reqfn)
                    fprintf(dsaresp,
                         "DSA key size must be a multiple of 64 between 512 "
                         "and 1024, inclusive");
                     goto loser;
                 }
             }
             continue;
         }
-        /* N = ... */
-        if (buf[0] == 'N') {
-            if (sscanf(buf, "N = %d", &count) != 1) {
+        /* Num = ... */
+        if (strncmp(buf, "Num", 3) == 0) {
+            if (sscanf(buf, "Num = %d", &count) != 1) {
                 goto loser;
             }
             for (i = 0; i < count; i++) {
+                int pgen_counter, qgen_counter;
+                SECItem firstseed = { 0 }, qseed = { 0 }, pseed = { 0 };
                 SECStatus rv;
 
                 if (type == FIPS186_1) {
                     rv = PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES,
                          &pqg, &vfy);
+                } else if (type == A_1_2_1) {
+                    rv = FREEBL_Test_PQG_ParamGenV3_p(L, N, 0, &pqg, &vfy,
+                                                      shanum, &pgen_counter, &qgen_counter,
+                                                      &firstseed, &pseed, &qseed);
+                } else if (type == A_1_1_2) {
+                    rv = PQG_ParamGenV2(L, N, 0, &pqg, &vfy);
                 } else {
-                    rv = PQG_ParamGenV2(L, N, N, &pqg, &vfy);
+                    /* A_2_1 -- Generate G when P and Q have been read */
+                    continue;
                 }
+
                 if (rv != SECSuccess) {
                     fprintf(dsaresp,
                             "ERROR: Unable to generate PQG parameters");
                     goto loser;
                 }
                 to_hex_str(buf, pqg->prime.data, pqg->prime.len);
                 fprintf(dsaresp, "P = %s\n", buf);
                 to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len);
                 fprintf(dsaresp, "Q = %s\n", buf);
-                to_hex_str(buf, pqg->base.data, pqg->base.len);
-                fprintf(dsaresp, "G = %s\n", buf);
 		if (type == FIPS186_1) {
+                    to_hex_str(buf, pqg->base.data, pqg->base.len);
+                    fprintf(dsaresp, "G = %s\n", buf);
                     to_hex_str(buf, vfy->seed.data, vfy->seed.len);
                     fprintf(dsaresp, "Seed = %s\n", buf);
                     fprintf(dsaresp, "c = %d\n", vfy->counter);
                     to_hex_str(buf, vfy->h.data, vfy->h.len);
                     fputs("H = ", dsaresp);
                     for (j=vfy->h.len; j< pqg->prime.len; j++) {
                 	fprintf(dsaresp, "00");
                     }
                     fprintf(dsaresp, "%s\n", buf);
+                } else if (type == A_1_2_1) {
+                    to_hex_str(buf, firstseed.data, firstseed.len);
+                    fprintf(dsaresp, "firstseed = %s\n", buf);
+                    to_hex_str(buf, pseed.data, pseed.len);
+                    fprintf(dsaresp, "pseed = %s\n", buf);
+                    to_hex_str(buf, qseed.data, qseed.len);
+                    fprintf(dsaresp, "qseed = %s\n", buf);
+                    fprintf(dsaresp, "pgen_counter = %d\n", pgen_counter);
+                    fprintf(dsaresp, "qgen_counter = %d\n", qgen_counter);
 		} else {
+                    to_hex_str(buf, pqg->base.data, pqg->base.len);
+                    fprintf(dsaresp, "G = %s\n", buf);
                     fprintf(dsaresp, "counter = %d\n", vfy->counter);
 		    fprintf(dsaresp, "index = %02x\n", vfy->h.data[0]);
                     to_hex_str(buf, vfy->seed.data, vfy->seed.len);
                     fprintf(dsaresp, "domain_parameter_seed = %s\n", buf);
 		}
+
                 fputc('\n', dsaresp);
+
                 if(pqg!=NULL) {
                     PQG_DestroyParams(pqg);
                     pqg = NULL;
                 }
                 if(vfy!=NULL) {
                     PQG_DestroyVerify(vfy);
                     vfy = NULL;
                 }
+
+                if (firstseed.data) {
+                    SECITEM_FreeItem(&firstseed, PR_FALSE);
+                    firstseed.data = NULL;
+                }
+                if (pseed.data) {
+                    SECITEM_FreeItem(&pseed, PR_FALSE);
+                    pseed.data = NULL;
+                }
+                if (qseed.data) {
+                    SECITEM_FreeItem(&qseed, PR_FALSE);
+                    qseed.data = NULL;
+                }
             }
 
             continue;
         }
 
+        /* P = ... */
+        if (buf[0] == 'P') {
+            unsigned char databuf [1024];
+            int len;
+
+            fputs(buf, dsaresp);
+
+            for (i = 1; isspace (buf [i]) || buf [i] == '='; i++)
+                ;
+
+            len = from_hex_str_varlen (databuf, 1024, &buf [i]);
+
+            P.type = siBuffer;
+            P.data = NULL;
+            P.len = 0;
+            SECITEM_AllocItem (NULL, &P, len);
+            memcpy (P.data, databuf, len);
+        }
+
+        /* Q = ... */
+        if (buf[0] == 'Q') {
+            unsigned char databuf [1024];
+            char hexbuf [1024];
+            int len;
+
+            fputs(buf, dsaresp);
+
+            for (i = 1; isspace (buf [i]) || buf [i] == '='; i++)
+                ;
+
+            len = from_hex_str_varlen (databuf, 1024, &buf [i]);
+
+            Q.type = siBuffer;
+            Q.data = NULL;
+            Q.len = 0;
+            SECITEM_AllocItem (NULL, &Q, len);
+            memcpy (Q.data, databuf, len);
+
+            /* Generate G from P and Q according to FIPS 186-3 A2.1 */
+            FREEBL_Test_PQG_GenerateG_p (L, N, 0, &pqg, &vfy, shanum, &P, &Q);
+
+            to_hex_str((char *) hexbuf, pqg->base.data, pqg->base.len);
+            fprintf(dsaresp, "G = %s\n", hexbuf);
+        }
     }
 loser:
     fclose(dsareq);
     if(pqg!=NULL) {
         PQG_DestroyParams(pqg);
     }
     if(vfy!=NULL) {
         PQG_DestroyVerify(vfy);
@@ -4395,17 +4583,17 @@ dsa_siggen_test(char *reqfn)
     HASH_HashType hashType = HASH_AlgNULL;
     int hashNum = 0;
 
     dsareq = fopen(reqfn, "r");
     dsaresp = stdout;
 
     while (fgets(buf, sizeof buf, dsareq) != NULL) {
         /* a comment or blank line */
-        if (buf[0] == '#' || buf[0] == '\n') {
+        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
             fputs(buf, dsaresp);
             continue;
         }
 
         /* [Mod = x] */
         if (buf[0] == '[') {
             if(pqg!=NULL) {
                 PQG_DestroyParams(pqg);
@@ -4424,17 +4612,16 @@ dsa_siggen_test(char *reqfn)
                 &hashNum) != 3) {
                 use_dsa1 = PR_TRUE;
 		hashNum = 1;
                 if (sscanf(buf, "[mod = %d]", &modulus) != 1) {
                     goto loser;
                 }
             }
             fputs(buf, dsaresp);
-            fputc('\n', dsaresp);
 
             /****************************************************************
             * PQG_ParamGenSeedLen doesn't take a key size, it takes an index
             * that points to a valid key size.
             */
             if (use_dsa1) {
                 keySizeIndex = PQG_PBITS_TO_INDEX(modulus);
                 if(keySizeIndex == -1 || modulus<512 || modulus>1024) {
@@ -4452,16 +4639,17 @@ dsa_siggen_test(char *reqfn)
                 }
             } else {
                 if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) {
                     fprintf(dsaresp, 
                             "ERROR: Unable to generate PQG parameters");
                     goto loser;
                 }
             }
+
             to_hex_str(buf, pqg->prime.data, pqg->prime.len);
             fprintf(dsaresp, "P = %s\n", buf);
             to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len);
             fprintf(dsaresp, "Q = %s\n", buf);
             to_hex_str(buf, pqg->base.data, pqg->base.len);
             fprintf(dsaresp, "G = %s\n", buf);
 
             /* create DSA Key */
@@ -4526,17 +4714,16 @@ dsa_siggen_test(char *reqfn)
             fputs(buf, dsaresp);
             to_hex_str(buf, dsakey->publicValue.data,
                        dsakey->publicValue.len);
             fprintf(dsaresp, "Y = %s\n", buf);
             to_hex_str(buf, &signature.data[0], len);
             fprintf(dsaresp, "R = %s\n", buf);
             to_hex_str(buf, &signature.data[len], len);
             fprintf(dsaresp, "S = %s\n", buf);
-            fputc('\n', dsaresp);
             continue;
         }
 
     }
 loser:
     fclose(dsareq);
     if(pqg != NULL) {
         PQG_DestroyParams(pqg);
@@ -4580,17 +4767,17 @@ dsa_sigver_test(char *reqfn)
     int hashNum = 0;
 
     dsareq = fopen(reqfn, "r");
     dsaresp = stdout;
     memset(&pubkey, 0, sizeof(pubkey));
 
     while (fgets(buf, sizeof buf, dsareq) != NULL) {
         /* a comment or blank line */
-        if (buf[0] == '#' || buf[0] == '\n') {
+        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
             fputs(buf, dsaresp);
             continue;
         }
 
         /* [Mod = x] */
         if (buf[0] == '[') {
 
             if (sscanf(buf, "[mod = L=%d,  N=%d, SHA-%d]", &L, & N,
@@ -4762,17 +4949,16 @@ dsa_sigver_test(char *reqfn)
             signature.data = sig;
             signature.len = pubkey.params.subPrime.len*2;
 
             if (DSA_VerifyDigest(&pubkey, &signature, &digest) == SECSuccess) {
                 fprintf(dsaresp, "Result = P\n");
             } else {
                 fprintf(dsaresp, "Result = F\n");
             }
-	    fprintf(dsaresp, "\n");
             continue;
         }
     }
 loser:
     fclose(dsareq);
     if (pubkey.params.prime.data) { /* P */
         SECITEM_ZfreeItem(&pubkey.params.prime, PR_FALSE);
     }
@@ -4783,16 +4969,140 @@ loser:
         SECITEM_ZfreeItem(&pubkey.params.base, PR_FALSE);
     }
     if (pubkey.publicValue.data) {    /* Y */
         SECITEM_ZfreeItem(&pubkey.publicValue, PR_FALSE);
     }
 }
 
 /*
+ * Perform the RSA Provable-prime key generation test
+ *
+ * reqfn is the pathname of the REQUEST file.
+ *
+ * The output RESPONSE file is written to stdout.
+ */
+void
+rsa_keygen_probable_test(char *reqfn)
+{
+    char buf[2*RSA_MAX_TEST_MODULUS_BYTES+1];
+                        /* buf holds one line from the input REQUEST file
+                         * or to the output RESPONSE file.
+                         * 2x for HEX output + 1 for \n
+                         */
+    FILE *rsareq;     /* input stream from the REQUEST file */
+    FILE *rsaresp;    /* output stream to the RESPONSE file */
+    int i;
+    int modulus;                                /* the Modulus size */
+    int  publicExponent  = DEFAULT_RSA_PUBLIC_EXPONENT;
+    SECItem pe = {0, 0, 0 };
+    unsigned char pubEx[4];
+    int peCount = 0;
+    RSAPrivateKey  *rsaBlapiPrivKey = NULL;   /* holds RSA private and
+                                               * public keys */
+
+    rsareq = fopen(reqfn, "r");
+    rsaresp = stdout;
+
+    /* calculate the exponent */
+    for (i=0; i < 4; i++) {
+        if (peCount || (publicExponent &
+                ((unsigned long)0xff000000L >> (i*8)))) {
+            pubEx[peCount] =
+                (unsigned char)((publicExponent >> (3-i)*8) & 0xff);
+            peCount++;
+        }
+    }
+    pe.len = peCount;
+    pe.data = &pubEx[0];
+    pe.type = siBuffer;
+
+    while (fgets(buf, sizeof buf, rsareq) != NULL) {
+        /* a comment or blank line */
+        if (buf[0] == '#' || buf[0] == '\n' || buf [0] == '\r') {
+            fputs(buf, rsaresp);
+            continue;
+        }
+
+        /* [PrimeMethod = ...] */
+        if (strncmp (buf, "[PrimeMethod", 4) == 0) {
+            /* PrimeMethod is always ProvRP */
+            fputs(buf, rsaresp);
+        }
+
+        /* [Table = ...] */
+        if (strncmp (buf, "[Table", 4) == 0) {
+            /* M-R Test table */
+            fputs(buf, rsaresp);
+        }
+
+        /* [mod = ...] */
+        if (strncmp (buf, "[mod", 4) == 0) {
+            if (sscanf(buf, "[mod = %d]", &modulus) != 1) {
+                goto loser;
+            }
+            if (modulus > RSA_MAX_TEST_MODULUS_BITS) {
+                fprintf(rsaresp,"ERROR: modulus greater than test maximum\n");
+                goto loser;
+            }
+
+            fputs(buf, rsaresp);
+        }
+
+        if (strncmp (buf, "N", 1) == 0) {
+            int count;
+            int i;
+
+            if (sscanf(buf, "N = %d", &count) != 1) {
+                goto loser;
+            }
+
+            for (i = 0; i < count; i++) {
+                if (rsaBlapiPrivKey != NULL) {
+                    PORT_FreeArena(rsaBlapiPrivKey->arena, PR_TRUE);
+                    rsaBlapiPrivKey = NULL;
+                }
+
+                rsaBlapiPrivKey = RSA_NewKey(modulus, &pe);
+                if (rsaBlapiPrivKey == NULL) {
+                    fprintf(rsaresp, "Error unable to create RSA key\n");
+                    goto loser;
+                }
+
+                to_hex_str(buf, rsaBlapiPrivKey->publicExponent.data,
+                           rsaBlapiPrivKey->publicExponent.len);
+                fprintf(rsaresp, "e = %s\n", buf);
+                to_hex_str(buf, rsaBlapiPrivKey->prime1.data,
+                           rsaBlapiPrivKey->prime1.len);
+                fprintf(rsaresp, "p = %s\n", buf);
+                to_hex_str(buf, rsaBlapiPrivKey->prime2.data,
+                           rsaBlapiPrivKey->prime2.len);
+                fprintf(rsaresp, "q = %s\n", buf);
+
+                to_hex_str(buf, rsaBlapiPrivKey->modulus.data,
+                           rsaBlapiPrivKey->modulus.len);
+                fprintf(rsaresp, "n = %s\n", buf);
+                to_hex_str_pad(buf, rsaBlapiPrivKey->privateExponent.data,
+                               rsaBlapiPrivKey->privateExponent.len,
+                               modulus / 8);
+                fprintf(rsaresp, "d = %s\n\n", buf);
+            }
+        }
+    }
+loser:
+    fclose(rsareq);
+
+    if (rsaBlapiPrivKey != NULL) {
+        /* frees private and public key */
+        PORT_FreeArena(rsaBlapiPrivKey->arena, PR_TRUE);
+        rsaBlapiPrivKey = NULL;
+    }
+}
+
+/*
  * Perform the RSA Signature Generation Test.
  *
  * reqfn is the pathname of the REQUEST file.
  *
  * The output RESPONSE file is written to stdout.
  */
 void
 rsa_siggen_test(char *reqfn)
@@ -4832,17 +5142,17 @@ rsa_siggen_test(char *reqfn)
         }
     }
     pe.len = peCount;
     pe.data = &pubEx[0];
     pe.type = siBuffer;
 
     while (fgets(buf, sizeof buf, rsareq) != NULL) {
         /* a comment or blank line */
-        if (buf[0] == '#' || buf[0] == '\n') {
+        if (buf[0] == '#' || buf[0] == '\n' || buf [0] == '\r') {
             fputs(buf, rsaresp);
             continue;
         }
 
         /* [mod = ...] */
         if (buf[0] == '[') {
 
             if (sscanf(buf, "[mod = %d]", &modulus) != 1) {
@@ -5030,17 +5340,17 @@ rsa_sigver_test(char *reqfn)
     RSAPublicKey   rsaBlapiPublicKey; /* hold RSA public key */
 
     rsareq = fopen(reqfn, "r");
     rsaresp = stdout;
     memset(&rsaBlapiPublicKey, 0, sizeof(RSAPublicKey));
 
     while (fgets(buf, sizeof buf, rsareq) != NULL) {
         /* a comment or blank line */
-        if (buf[0] == '#' || buf[0] == '\n') {
+        if (buf[0] == '#' || buf[0] == '\n' || buf [0] == '\r') {
             fputs(buf, rsaresp);
             continue;
         }
 
         /* [Mod = ...] */
         if (buf[0] == '[') {
             unsigned int flen;  /* length in bytes of the field size */
 
@@ -5101,16 +5411,17 @@ rsa_sigver_test(char *reqfn)
            } else if (strncmp(&buf[i], "SHA384", 6) == 0) {
                shaAlg = HASH_AlgSHA384;
            } else if (strncmp(&buf[i], "SHA512", 6) == 0) {
                shaAlg = HASH_AlgSHA512;
            } else {
                fprintf(rsaresp, "ERROR: Unable to find SHAAlg type");
                goto loser;
            }
+           shaOid = fips_hashOid(shaAlg);
            fputs(buf, rsaresp);
            continue;
         }
 
         /* e = ... public Key */
         if (buf[0] == 'e') {
             unsigned char data[RSA_MAX_TEST_EXPONENT_BYTES];
             unsigned char t;
@@ -5228,22 +5539,57 @@ loser:
     if (rsaBlapiPublicKey.modulus.data) { /* n */
         SECITEM_ZfreeItem(&rsaBlapiPublicKey.modulus, PR_FALSE);
     }
     if (rsaBlapiPublicKey.publicExponent.data) { /* e */
         SECITEM_ZfreeItem(&rsaBlapiPublicKey.publicExponent, PR_FALSE);
     }
 }
 
+static void
+init_functions (void)
+{
+    void *freebl_so;
+
+    freebl_so = dlopen ("libfreebl3.so", RTLD_LAZY);
+    if (freebl_so == NULL)
+    {
+        fprintf (stderr, "Failed to load libfreebl3.so.");
+        exit (1);
+    }
+
+    FREEBL_GetGlobalVar_p = dlsym (freebl_so, "FREEBL_GetGlobalVar");
+    FREEBL_Test_PQG_ParamGenV3_p = dlsym (freebl_so, "FREEBL_Test_PQG_ParamGenV3");
+    FREEBL_Test_PQG_GenerateG_p = dlsym (freebl_so, "FREEBL_Test_PQG_GenerateG");
+
+    if (FREEBL_GetGlobalVar_p == NULL)
+    {
+        fprintf (stderr, "Failed to bind FREEBL_GetGlobalVar.");
+        exit (1);
+    }
+    if (FREEBL_Test_PQG_ParamGenV3_p == NULL)
+    {
+        fprintf (stderr, "Failed to bind FREEBL_TEST_PQG_ParamGenV3.");
+        exit (1);
+    }
+    if (FREEBL_Test_PQG_GenerateG_p == NULL)
+    {
+        fprintf (stderr, "Failed to bind FREEBL_TEST_PQG_GenerateG.");
+        exit (1);
+    }
+}
+
 int main(int argc, char **argv)
 {
     if (argc < 2) exit (-1);
 
+    init_functions ();
     RNG_RNGInit();
     SECOID_Init();
+    BL_Init();
 
     /*************/
     /*   TDEA    */
     /*************/
     if (strcmp(argv[1], "tdea") == 0) {
         /* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=<test name>.req */
         if (strcmp(argv[2], "kat") == 0) {
             /* Known Answer Test (KAT) */
@@ -5294,16 +5640,19 @@ int main(int argc, char **argv)
         /* argv[2]=siggen|sigver */
         /* argv[3]=<test name>.req */
         if (strcmp(argv[2], "siggen") == 0) {
             /* Signature Generation Test */
             rsa_siggen_test(argv[3]);
         } else if (strcmp(argv[2], "sigver") == 0) {
             /* Signature Verification Test */
             rsa_sigver_test(argv[3]);
+        } else if (strcmp(argv[2], "keygen") == 0) {
+            /* Key Generation Test with probable primes */
+            rsa_keygen_probable_test(argv[3]);
         }
     /*************/
     /*   HMAC    */
     /*************/
     } else if (strcmp(argv[1], "hmac") == 0) {
         hmac_test(argv[2]);
     /*************/
     /*   DSA     */
diff --git a/cmd/fipstest/rng.sh b/cmd/fipstest/rng.sh
old mode 100644
new mode 100755
--- a/cmd/fipstest/rng.sh
+++ b/cmd/fipstest/rng.sh
@@ -8,16 +8,16 @@
 #
 # Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment
 # variables appropriately so that the fipstest command and the NSPR and NSS
 # shared libraries/DLLs are on the search path.  Then run this script in the
 # directory where the REQUEST (.req) files reside.  The script generates the
 # RESPONSE (.rsp) files in the same directory.
 
 drbg_requests="
-SHA256_DRBG.req
+Hash_DRBG.req
 "
 
 for request in $drbg_requests; do
     response=`echo $request | sed -e "s/req/rsp/"`
     echo $request $response
     fipstest drbg $request > $response
 done
diff --git a/cmd/fipstest/rsa.sh b/cmd/fipstest/rsa.sh
old mode 100644
new mode 100755
--- a/cmd/fipstest/rsa.sh
+++ b/cmd/fipstest/rsa.sh
@@ -8,17 +8,22 @@
 #
 # Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment
 # variables appropriately so that the fipstest command and the NSPR and NSS
 # shared libraries/DLLs are on the search path.  Then run this script in the
 # directory where the REQUEST (.req) files reside.  The script generates the
 # RESPONSE (.rsp) files in the same directory.
 
 
-request=SigGen15.req
+request=SigGen15_186-3.req
 response=`echo $request | sed -e "s/req/rsp/"`
 echo $request $response
 fipstest rsa siggen $request > $response
 
-request=SigVer15.req
+request=SigVer15_186-3.req
 response=`echo $request | sed -e "s/req/rsp/"`
 echo $request $response
 fipstest rsa sigver $request > $response
+
+request=KeyGen_RandomProbablyPrime3_3.req
+response=`echo $request | sed -e "s/req/rsp/"`
+echo $request $response
+fipstest rsa keygen $request > $response
diff --git a/cmd/fipstest/sha.sh b/cmd/fipstest/sha.sh
old mode 100644
new mode 100755
--- a/cmd/fipstest/sha.sh
+++ b/cmd/fipstest/sha.sh
@@ -9,30 +9,33 @@
 # Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment
 # variables appropriately so that the fipstest command and the NSPR and NSS
 # shared libraries/DLLs are on the search path.  Then run this script in the
 # directory where the REQUEST (.req) files reside.  The script generates the
 # RESPONSE (.rsp) files in the same directory.
                                
 sha_ShortMsg_requests="
 SHA1ShortMsg.req
+SHA224ShortMsg.req
 SHA256ShortMsg.req
 SHA384ShortMsg.req
 SHA512ShortMsg.req
 "
 
 sha_LongMsg_requests="
 SHA1LongMsg.req
+SHA224LongMsg.req
 SHA256LongMsg.req
 SHA384LongMsg.req
 SHA512LongMsg.req
 "
 
 sha_Monte_requests="
 SHA1Monte.req
+SHA224Monte.req
 SHA256Monte.req
 SHA384Monte.req
 SHA512Monte.req
 "
 for request in $sha_ShortMsg_requests; do
     response=`echo $request | sed -e "s/req/rsp/"`
     echo $request $response
     fipstest sha $request > $response
diff --git a/cmd/pk11gcmtest/pk11gcmtest.c b/cmd/pk11gcmtest/pk11gcmtest.c
--- a/cmd/pk11gcmtest/pk11gcmtest.c
+++ b/cmd/pk11gcmtest/pk11gcmtest.c
@@ -28,16 +28,42 @@ hex_to_byteval(const char *c2, unsigned 
 	    *byteval |= (offset + 10) << 4*(1-i);
 	} else {
 	    return SECFailure;
 	}
     }
     return SECSuccess;
 }
 
+SECStatus
+byteval_to_hex(unsigned char byteval, char *c2, char a)
+{
+    int i;
+    unsigned char offset;
+    for (i=0; i<2; i++) {
+	offset = (byteval >> 4*(1-i)) & 0x0f;
+	if (offset < 10) {
+	    c2[i] = '0' + offset;
+	} else {
+	    c2[i] = a + offset - 10;
+	}
+    }
+    return SECSuccess;
+}
+
+void
+to_hex_str(char *str, const unsigned char *buf, unsigned int len)
+{
+    unsigned int i;
+    for (i=0; i<len; i++) {
+	byteval_to_hex(buf[i], &str[2*i], 'a');
+    }
+    str[2*len] = '\0';
+}
+
 static SECStatus
 aes_encrypt_buf(
     const unsigned char *key, unsigned int keysize,
     const unsigned char *iv, unsigned int ivsize,
     unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
     const unsigned char *input, unsigned int inputlen,
     const unsigned char *aad, unsigned int aadlen, unsigned int tagsize)
 {
@@ -117,17 +143,19 @@ aes_decrypt_buf(
     key_item.data = (unsigned char *) key;  /* const cast */
     key_item.len = keysize;
     slot = PK11_GetInternalSlot();
     symKey = PK11_ImportSymKey(slot, CKM_AES_GCM, PK11_OriginUnwrap,
 			       CKA_DECRYPT, &key_item, NULL);
     PK11_FreeSlot(slot);
     slot = NULL;
     if (!symKey) {
+#if 0
 	fprintf(stderr, "PK11_ImportSymKey failed\n");
+#endif
 	goto loser;
     }
 
     gcm_params.pIv = (unsigned char *) iv;
     gcm_params.ulIvLen = ivsize;
     gcm_params.pAAD = (unsigned char *) aad;
     gcm_params.ulAADLen = aadlen;
     gcm_params.ulTagBits = tagsize * 8;
@@ -149,26 +177,27 @@ loser:
 	PK11_FreeSymKey(symKey);
     }
     return rv;
 }
 
 /*
  * Perform the AES Known Answer Test (KAT) in Galois Counter Mode (GCM).
  *
- * respfn is the pathname of the RESPONSE file.
+ * reqfn is the pathname of the RESPONSE file.
  */
 static void
-aes_gcm_kat(const char *respfn)
+aes_gcm_kat(const char *reqfn)
 {
     char buf[512];      /* holds one line from the input REQUEST file.
                          * needs to be large enough to hold the longest
                          * line "CIPHERTEXT = <320 hex digits>\n".
                          */
-    FILE *aesresp;      /* input stream from the RESPONSE file */
+    FILE *aesreq;       /* input stream from the REQUEST file */
+    FILE *aesresp;      /* output stream to the RESPONSE file */
     int i, j;
     unsigned int test_group = 0;
     unsigned int num_tests;
     PRBool is_encrypt;
     unsigned char key[32];              /* 128, 192, or 256 bits */
     unsigned int keysize;
     unsigned char iv[10*16];            /* 1 to 10 blocks */
     unsigned int ivsize;
@@ -185,32 +214,34 @@ aes_gcm_kat(const char *respfn)
 
     unsigned int expected_keylen = 0;
     unsigned int expected_ivlen = 0;
     unsigned int expected_ptlen = 0;
     unsigned int expected_aadlen = 0;
     unsigned int expected_taglen = 0;
     SECStatus rv;
 
-    if (strstr(respfn, "Encrypt") != NULL) {
+    if (strstr(reqfn, "Encrypt") != NULL) {
 	is_encrypt = PR_TRUE;
-    } else if (strstr(respfn, "Decrypt") != NULL) {
+    } else if (strstr(reqfn, "Decrypt") != NULL) {
 	is_encrypt = PR_FALSE;
     } else {
 	fprintf(stderr, "Input file name must contain Encrypt or Decrypt\n");
 	exit(1);
     }
-    aesresp = fopen(respfn, "r");
-    if (aesresp == NULL) {
-	fprintf(stderr, "Cannot open input file %s\n", respfn);
+    aesreq = fopen(reqfn, "r");
+    if (aesreq == NULL) {
+	fprintf(stderr, "Cannot open input file %s\n", reqfn);
 	exit(1);
     }
-    while (fgets(buf, sizeof buf, aesresp) != NULL) {
+    aesresp = stdout;
+    while (fgets(buf, sizeof buf, aesreq) != NULL) {
 	/* a comment or blank line */
-	if (buf[0] == '#' || buf[0] == '\n') {
+	if (buf[0] == '#' || buf[0] == '\n' || buf [0] == '\r') {
+	    fputs(buf, aesresp);
 	    continue;
 	}
 	/* [Keylen = ...], [IVlen = ...], etc. */
 	if (buf[0] == '[') {
 	    if (strncmp(&buf[1], "Keylen = ", 9) == 0) {
 		expected_keylen = atoi(&buf[10]);
 	    } else if (strncmp(&buf[1], "IVlen = ", 8) == 0) {
 		expected_ivlen = atoi(&buf[9]);
@@ -218,38 +249,43 @@ aes_gcm_kat(const char *respfn)
 		expected_ptlen = atoi(&buf[9]);
 	    } else if (strncmp(&buf[1], "AADlen = ", 9) == 0) {
 		expected_aadlen = atoi(&buf[10]);
 	    } else if (strncmp(&buf[1], "Taglen = ", 9) == 0) {
 		expected_taglen = atoi(&buf[10]);
 
 		test_group++;
 		if (test_group > 1) {
+#if 0
 		    /* Report num_tests for the previous test group. */
 		    printf("%u tests\n", num_tests);
+#endif
 		}
 		num_tests = 0;
+#if 0
 		printf("Keylen = %u, IVlen = %u, PTlen = %u, AADlen = %u, "
 		       "Taglen = %u: ", expected_keylen, expected_ivlen,
 		        expected_ptlen, expected_aadlen, expected_taglen);
+#endif
 		/* Convert lengths in bits to lengths in bytes. */
 		PORT_Assert(expected_keylen % 8 == 0);
 		expected_keylen /= 8;
 		PORT_Assert(expected_ivlen % 8 == 0);
 		expected_ivlen /= 8;
 		PORT_Assert(expected_ptlen % 8 == 0);
 		expected_ptlen /= 8;
 		PORT_Assert(expected_aadlen % 8 == 0);
 		expected_aadlen /= 8;
 		PORT_Assert(expected_taglen % 8 == 0);
 		expected_taglen /= 8;
 	    } else {
 		fprintf(stderr, "Unexpected input line: %s\n", buf);
 		exit(1);
 	    }
+	    fputs(buf, aesresp);
 	    continue;
 	}
 	/* "Count = x" begins a new data set */
 	if (strncmp(buf, "Count", 5) == 0) {
 	    /* zeroize the variables for the test with this data set */
 	    memset(key, 0, sizeof key);
 	    keysize = 0;
 	    memset(iv, 0, sizeof iv);
@@ -258,16 +294,17 @@ aes_gcm_kat(const char *respfn)
 	    plaintextlen = 0;
 	    memset(aad, 0, sizeof aad);
 	    aadlen = 0;
 	    memset(ciphertext, 0, sizeof ciphertext);
 	    ciphertextlen = 0;
 	    memset(output, 0, sizeof output);
 	    outputlen = 0;
 	    num_tests++;
+	    fputs(buf, aesresp);
 	    continue;
 	}
 	/* Key = ... */
 	if (strncmp(buf, "Key", 3) == 0) {
 	    i = 3;
 	    while (isspace(buf[i]) || buf[i] == '=') {
 		i++;
 	    }
@@ -275,16 +312,17 @@ aes_gcm_kat(const char *respfn)
 		hex_to_byteval(&buf[i], &key[j]);
 	    }
 	    keysize = j;
 	    if (keysize != expected_keylen) {
 		fprintf(stderr, "Unexpected key length: %u vs. %u\n",
 			keysize, expected_keylen);
 		exit(1);
 	    }
+	    fputs(buf, aesresp);
 	    continue;
 	}
 	/* IV = ... */
 	if (strncmp(buf, "IV", 2) == 0) {
 	    i = 2;
 	    while (isspace(buf[i]) || buf[i] == '=') {
 		i++;
 	    }
@@ -292,16 +330,17 @@ aes_gcm_kat(const char *respfn)
 		hex_to_byteval(&buf[i], &iv[j]);
 	    }
 	    ivsize = j;
 	    if (ivsize != expected_ivlen) {
 		fprintf(stderr, "Unexpected IV length: %u vs. %u\n",
 			ivsize, expected_ivlen);
 		exit(1);
 	    }
+	    fputs(buf, aesresp);
 	    continue;
 	}
 	/* PT = ... */
 	if (strncmp(buf, "PT", 2) == 0) {
 	    i = 2;
 	    while (isspace(buf[i]) || buf[i] == '=') {
 		i++;
 	    }
@@ -310,33 +349,17 @@ aes_gcm_kat(const char *respfn)
 	    }
 	    plaintextlen = j;
 	    if (plaintextlen != expected_ptlen) {
 		fprintf(stderr, "Unexpected PT length: %u vs. %u\n",
 			plaintextlen, expected_ptlen);
 		exit(1);
 	    }
 
-	    if (!is_encrypt) {
-		rv = aes_decrypt_buf(key, keysize, iv, ivsize,
-		    output, &outputlen, sizeof output,
-		    ciphertext, ciphertextlen, aad, aadlen, tag, tagsize);
-		if (rv != SECSuccess) {
-		    fprintf(stderr, "aes_decrypt_buf failed\n");
-		    goto loser;
-		}
-		if (outputlen != plaintextlen) {
-		    fprintf(stderr, "aes_decrypt_buf: wrong output size\n");
-		    goto loser;
-		}
-		if (memcmp(output, plaintext, plaintextlen) != 0) {
-		    fprintf(stderr, "aes_decrypt_buf: wrong plaintext\n");
-		    goto loser;
-		}
-	    }
+	    fputs(buf, aesresp);
 	    continue;
 	}
 	/* FAIL */
 	if (strncmp(buf, "FAIL", 4) == 0) {
 	    plaintextlen = 0;
 
 	    PORT_Assert(!is_encrypt);
 	    rv = aes_decrypt_buf(key, keysize, iv, ivsize,
@@ -363,16 +386,56 @@ aes_gcm_kat(const char *respfn)
 		hex_to_byteval(&buf[i], &aad[j]);
 	    }
 	    aadlen = j;
 	    if (aadlen != expected_aadlen) {
 		fprintf(stderr, "Unexpected AAD length: %u vs. %u\n",
 			aadlen, expected_aadlen);
 		exit(1);
 	    }
+
+	    fputs(buf, aesresp);
+
+	    if (is_encrypt) {
+		rv = aes_encrypt_buf(key, keysize, iv, ivsize,
+		    output, &outputlen, sizeof output,
+		    plaintext, plaintextlen, aad, aadlen, expected_taglen);
+		if (rv != SECSuccess) {
+		    fprintf(stderr, "aes_encrypt_buf failed\n");
+		    goto loser;
+		}
+		if (outputlen != plaintextlen + expected_taglen) {
+		    fprintf(stderr, "aes_encrypt_buf: wrong output size\n");
+		    goto loser;
+		}
+#if 0
+                /* XXX Don't try to compare the ciphertext, as there is none
+                 * to compare with. Just output the resulting CT. */
+		if (memcmp(output, ciphertext, plaintextlen) != 0) {
+		    fprintf(stderr, "aes_encrypt_buf: wrong ciphertext\n");
+		    goto loser;
+		}
+
+		if (memcmp(output + plaintextlen, tag, tagsize) != 0) {
+		    fprintf(stderr, "aes_encrypt_buf: wrong tag\n");
+		    goto loser;
+		}
+#endif
+
+                fputs ("CT = ", aesresp);
+                to_hex_str (buf, output, plaintextlen);
+                fputs (buf, aesresp);
+                fputc ('\n', aesresp);
+
+                fputs ("Tag = ", aesresp);
+                to_hex_str (buf, output + plaintextlen, expected_taglen);
+                fputs (buf, aesresp);
+                fputc ('\n', aesresp);
+	    }
+
 	    continue;
 	}
 	/* CT = ... */
 	if (strncmp(buf, "CT", 2) == 0) {
 	    i = 2;
 	    while (isspace(buf[i]) || buf[i] == '=') {
 		i++;
 	    }
@@ -380,16 +443,18 @@ aes_gcm_kat(const char *respfn)
 		hex_to_byteval(&buf[i], &ciphertext[j]);
 	    }
 	    ciphertextlen = j;
 	    if (ciphertextlen != expected_ptlen) {
 		fprintf(stderr, "Unexpected CT length: %u vs. %u\n",
 			ciphertextlen, expected_ptlen);
 		exit(1);
 	    }
+
+	    fputs(buf, aesresp);
 	    continue;
 	}
 	/* Tag = ... */
 	if (strncmp(buf, "Tag", 3) == 0) {
 	    i = 3;
 	    while (isspace(buf[i]) || buf[i] == '=') {
 		i++;
 	    }
@@ -398,46 +463,54 @@ aes_gcm_kat(const char *respfn)
 	    }
 	    tagsize = j;
 	    if (tagsize != expected_taglen) {
 		fprintf(stderr, "Unexpected tag length: %u vs. %u\n",
 			tagsize, expected_taglen);
 		exit(1);
 	    }
 
-	    if (is_encrypt) {
-		rv = aes_encrypt_buf(key, keysize, iv, ivsize,
+	    fputs(buf, aesresp);
+
+	    if (!is_encrypt) {
+		rv = aes_decrypt_buf(key, keysize, iv, ivsize,
 		    output, &outputlen, sizeof output,
-		    plaintext, plaintextlen, aad, aadlen, tagsize);
-		if (rv != SECSuccess) {
-		    fprintf(stderr, "aes_encrypt_buf failed\n");
+		    ciphertext, ciphertextlen, aad, aadlen, tag, tagsize);
+		if (rv != SECSuccess || outputlen < expected_ptlen) {
+                    fputs ("FAIL\n", aesresp);
+		} else {
+                    fputs ("PT = ", aesresp);
+                    to_hex_str (buf, output, expected_ptlen);
+                    fputs (buf, aesresp);
+                    fputc ('\n', aesresp);
+                }
+
+#if 0
+                /* XXX Nothing to compare against */
+
+		if (memcmp(output, plaintext, plaintextlen) != 0) {
+		    fprintf(stderr, "aes_decrypt_buf: wrong plaintext\n");
 		    goto loser;
 		}
-		if (outputlen != plaintextlen + tagsize) {
-		    fprintf(stderr, "aes_encrypt_buf: wrong output size\n");
-		    goto loser;
-		}
-		if (memcmp(output, ciphertext, plaintextlen) != 0) {
-		    fprintf(stderr, "aes_encrypt_buf: wrong ciphertext\n");
-		    goto loser;
-		}
-		if (memcmp(output + plaintextlen, tag, tagsize) != 0) {
-		    fprintf(stderr, "aes_encrypt_buf: wrong tag\n");
-		    goto loser;
-		}
+#endif
 	    }
+
 	    continue;
 	}
     }
+
+#if 0
     /* Report num_tests for the last test group. */
     printf("%u tests\n", num_tests);
     printf("%u test groups\n", test_group);
     printf("PASS\n");
+#endif
+
 loser:
-    fclose(aesresp);
+    fclose(aesreq);
 }
 
 int main(int argc, char **argv)
 {
     if (argc < 2) exit(1);
 
     NSS_NoDB_Init(NULL);
 
diff --git a/lib/freebl/fips.h b/lib/freebl/fips.h
--- a/lib/freebl/fips.h
+++ b/lib/freebl/fips.h
@@ -3,27 +3,35 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef FIPS_H
 #define FIPS_H
 
+#include "blapit.h"
 #include "hasht.h"
-#include "secerr.h"
 
 #define IN_FIPS_RETURN(rv) \
     do { \
 	if (FIPS_mode()) { \
 	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); \
 	    return rv; \
 	} \
     } while (0)
 
 int	FIPS_mode(void);
 char*	FIPS_rngDev(void);
 PRBool	FIPS_hashAlgApproved(HASH_HashType hashAlg);
 
 void*	FREEBL_GetGlobalVar(int which, void *data);
 
+SECStatus FREEBL_Test_PQG_ParamGenV3 (unsigned int L, unsigned int N, unsigned int seedBytes,
+                                      PQGParams **pParams, PQGVerify **pVfy,
+                                      int shanum, int *pgen_counter, int *qgen_counter,
+                                      SECItem *firstseed, SECItem *pseed, SECItem *qseed);
+SECStatus FREEBL_Test_PQG_GenerateG (unsigned int L, unsigned int N, unsigned int seedBytes,
+                                     PQGParams **pParams, PQGVerify **pVfy,
+                                     int shanum, const SECItem *P, const SECItem *Q);
+
 #endif
 
diff --git a/lib/freebl/freebl.def b/lib/freebl/freebl.def
--- a/lib/freebl/freebl.def
+++ b/lib/freebl/freebl.def
@@ -17,11 +17,13 @@
 ;+#   directives are hidden behind ";", ";+", and ";-"
 ;+
 ;+NSSprivate_3.11 {               # NSS 3.11 release
 ;+    global:
 LIBRARY freebl3 ;-
 EXPORTS	;-
 FREEBL_GetVector;
 FREEBL_GetGlobalVar;
+FREEBL_Test_PQG_GenerateG;
+FREEBL_Test_PQG_ParamGenV3;
 ;+    local:
 ;+       *;
 ;+};
diff --git a/lib/freebl/freebl_hash.def b/lib/freebl/freebl_hash.def
--- a/lib/freebl/freebl_hash.def
+++ b/lib/freebl/freebl_hash.def
@@ -17,16 +17,18 @@
 ;+#   directives are hidden behind ";", ";+", and ";-"
 ;+
 ;+NSSprivate_3.11 {               # NSS 3.11 release
 ;+    global:
 LIBRARY freebl3 ;-
 EXPORTS	;-
 FREEBL_GetVector;
 FREEBL_GetGlobalVar;
+FREEBL_Test_PQG_GenerateG;
+FREEBL_Test_PQG_ParamGenV3;
 ;+    local:
 ;+       *;
 ;+};
 ;+NSSRAWHASH_3.12.3 {             # NSS 3.12.3 release
 ;+    global:
 NSSLOW_Init;
 NSSLOW_Shutdown;
 NSSLOWHASH_Length;
diff --git a/lib/freebl/pqg.c b/lib/freebl/pqg.c
--- a/lib/freebl/pqg.c
+++ b/lib/freebl/pqg.c
@@ -1223,17 +1223,21 @@ cleanup:
 
 /* This code uses labels and gotos, so that it can follow the numbered
 ** steps in the algorithms from FIPS 186-3 appendix A.1.1.2 very closely,
 ** and so that the correctness of this code can be easily verified.
 ** So, please forgive the ugly c code.
 **/
 static SECStatus
 pqg_ParamGen(unsigned int L, unsigned int N, pqgGenType type,
-	 unsigned int seedBytes, PQGParams **pParams, PQGVerify **pVfy)
+             unsigned int seedBytes, PQGParams **pParams, PQGVerify **pVfy,
+             const SECItem *P_in, const SECItem *Q_in,
+             int minHashLen, int *pgen_counter_out,
+             int *qgen_counter_out, SECItem *firstseed_out,
+             SECItem *pseed_out, SECItem *qseed_out)
 {
     unsigned int  n;        /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */
     unsigned int  b;        /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */
     unsigned int  seedlen;  /* Per FIPS 186-3 app A.1.1.2  (was 'g' 186-1)*/
     unsigned int  counter;  /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */
     unsigned int  offset;   /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */
     unsigned int  outlen;   /* Per FIPS 186-3, appendix A.1.1.2. */
     unsigned int  maxCount;
@@ -1247,17 +1251,16 @@ pqg_ParamGen(unsigned int L, unsigned in
     SECItem firstseed = { 0, 0, 0 };
     SECItem qseed = { 0, 0, 0 };
     SECItem pseed = { 0, 0, 0 };
     mp_int P, Q, G, H, l, p0;
     mp_err    err = MP_OKAY;
     SECStatus rv  = SECFailure;
     int iterations = 0;
 
-
     /* Step 1. L and N already checked by caller*/
     /* Step 2. if (seedlen < N) return INVALID; */
     if (seedBytes < N/PR_BITS_PER_BYTE || !pParams || !pVfy) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	return SECFailure;
     }
     /* Initialize an arena for the params. */
     arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
@@ -1298,20 +1301,27 @@ pqg_ParamGen(unsigned int L, unsigned in
     MP_DIGITS(&p0) = 0;
     CHECK_MPI_OK( mp_init(&P) );
     CHECK_MPI_OK( mp_init(&Q) );
     CHECK_MPI_OK( mp_init(&G) );
     CHECK_MPI_OK( mp_init(&H) );
     CHECK_MPI_OK( mp_init(&l) );
     CHECK_MPI_OK( mp_init(&p0) );
 
+    if (P_in && Q_in && P_in->data && Q_in->data &&
+        P_in->len > 0 && Q_in->len > 0) {
+        SECITEM_TO_MPINT(*P_in, &P);
+        SECITEM_TO_MPINT(*Q_in, &Q);
+        goto generate_G;
+    }
+
     /* Select Hash and Compute lengths. */
     /* getFirstHash gives us the smallest acceptable hash for this key
      * strength */
-    hashtype = getFirstHash(L,N);
+    hashtype = getFirstHash(L, minHashLen > N ? minHashLen : N);
     outlen = HASH_ResultLen(hashtype)*PR_BITS_PER_BYTE;
 
     /* Step 3: n = Ceil(L/outlen)-1; (same as n = Floor((L-1)/outlen)) */
     n = (L - 1) / outlen; 
     /* Step 4: b = L -1 - (n*outlen); (same as n = (L-1) mod outlen) */
     b = (L - 1) % outlen;
     seedlen = seedBytes * PR_BITS_PER_BYTE;    /* bits in seed */
 step_5:
@@ -1375,16 +1385,21 @@ step_5:
 	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; */
 
+        if (pgen_counter_out)
+            *pgen_counter_out = pgen_counter;
+        if (qgen_counter_out)
+            *qgen_counter_out = qgen_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."
     **
     ** Appendix 2.1 states that a Rabin test with at least 50 iterations
@@ -1494,16 +1509,24 @@ generate_G:
     }
     /* All generation is done.  Now, save the PQG params.  */
     MPINT_TO_SECITEM(&P, &params->prime,    params->arena);
     MPINT_TO_SECITEM(&Q, &params->subPrime, params->arena);
     MPINT_TO_SECITEM(&G, &params->base,     params->arena);
     verify->counter = counter;
     *pParams = params;
     *pVfy = verify;
+
+    if (firstseed_out)
+        SECITEM_CopyItem (NULL, firstseed_out, &firstseed);
+    if (qseed_out)
+        SECITEM_CopyItem (NULL, qseed_out, &qseed);
+    if (pseed_out)
+        SECITEM_CopyItem (NULL, pseed_out, &pseed);
+
 cleanup:
     if (pseed.data) {
 	PORT_Free(pseed.data);
     }
     if (qseed.data) {
 	PORT_Free(qseed.data);
     }
     mp_clear(&P);
@@ -1533,53 +1556,102 @@ PQG_ParamGen(unsigned int j, PQGParams *
     unsigned int seedBytes;
 
     if (j > 8 || !pParams || !pVfy) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
     L = 512 + (j * 64);         /* bits in P */
     seedBytes = L/8;
-    return pqg_ParamGen(L, DSA1_Q_BITS, FIPS186_1_TYPE, seedBytes, 
-                        pParams, pVfy);
+    return pqg_ParamGen(L, DSA1_Q_BITS, FIPS186_1_TYPE, seedBytes, pParams, pVfy,
+                        NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
 }
 
 SECStatus
 PQG_ParamGenSeedLen(unsigned int j, unsigned int seedBytes,
                     PQGParams **pParams, PQGVerify **pVfy)
 {
     unsigned int L;            /* Length of P in bits.  Per FIPS 186. */
 
     if (j > 8 || !pParams || !pVfy) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
     L = 512 + (j * 64);         /* bits in P */
-    return pqg_ParamGen(L, DSA1_Q_BITS, FIPS186_1_TYPE, seedBytes,
-                        pParams, pVfy);
+    return pqg_ParamGen(L, DSA1_Q_BITS, FIPS186_1_TYPE, seedBytes, pParams, pVfy,
+                        NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
 }
 
 SECStatus
 PQG_ParamGenV2(unsigned int L, unsigned int N, unsigned int seedBytes,
-                    PQGParams **pParams, PQGVerify **pVfy)
+               PQGParams **pParams, PQGVerify **pVfy)
 {
     if (N == 0) {
 	N = pqg_get_default_N(L);
     }
     if (seedBytes == 0) {
 	/* seedBytes == L/8 for probable primes, N/8 for Shawe-Taylor Primes */
 	seedBytes = N/8;
     }
     if (pqg_validate_dsa2(L,N) != SECSuccess) {
 	/* error code already set */
 	return SECFailure;
     }
-    return pqg_ParamGen(L, N, FIPS186_3_ST_TYPE, seedBytes, pParams, pVfy);
+    return pqg_ParamGen(L, N, FIPS186_3_ST_TYPE, seedBytes, pParams, pVfy,
+                        NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
 }
 
+SECStatus
+FREEBL_Test_PQG_ParamGenV3(unsigned int L, unsigned int N, unsigned int seedBytes,
+                           PQGParams **pParams, PQGVerify **pVfy,
+                           int shanum, int *pgen_counter, int *qgen_counter,
+                           SECItem *firstseed, SECItem *pseed, SECItem *qseed)
+{
+    if (N == 0) {
+	N = pqg_get_default_N(L);
+    }
+    if (seedBytes == 0) {
+	/* seedBytes == L/8 for probable primes, N/8 for Shawe-Taylor Primes */
+	seedBytes = N/8;
+    }
+    if (pqg_validate_dsa2(L,N) != SECSuccess) {
+	/* error code already set */
+	return SECFailure;
+    }
+
+    return pqg_ParamGen(L, N, FIPS186_3_ST_TYPE, seedBytes, pParams, pVfy,
+                        NULL, NULL, shanum, pgen_counter, qgen_counter, firstseed, pseed, qseed);
+}
+
+/* Only to be used by FIPS tests */
+SECStatus
+FREEBL_Test_PQG_GenerateG (unsigned int L, unsigned int N, unsigned int seedBytes,
+                           PQGParams **pParams, PQGVerify **pVfy,
+                           int shanum, const SECItem *P, const SECItem *Q)
+{
+    int rv;
+
+    /* Generate G from P and Q according to FIPS 186-3 A2.1 */
+
+    if (N == 0) {
+	N = pqg_get_default_N(L);
+    }
+
+    if (seedBytes == 0) {
+	/* seedBytes == L/8 for probable primes, N/8 for Shawe-Taylor Primes */
+	seedBytes = N/8;
+    }
+    if (pqg_validate_dsa2(L,N) != SECSuccess) {
+	/* error code already set */
+	return SECFailure;
+    }
+
+    return pqg_ParamGen (L, N, FIPS186_1_TYPE, seedBytes, pParams, pVfy,
+                         P, Q, shanum, NULL, NULL, NULL, NULL, NULL);
+}
 
 /*
  * verify can use vfy structures returned from either FIPS186-1 or
  * FIPS186-2, and can handle differences in selected Hash functions to
  * generate the parameters.
  */
 SECStatus   
 PQG_VerifyParams(const PQGParams *params, 
