# HG changeset patch
# Parent  27661bdc65050f356ed2603821400839950eb01b
extend CAVS test to provide what it takes for certification

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,40 +1223,43 @@ 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  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  counter = 0;	/* 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;
-    HASH_HashType hashtype;
+    HASH_HashType hashtype = HASH_AlgNULL;
     SECItem      *seed;     /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */
     PLArenaPool  *arena  = NULL;
     PQGParams    *params = NULL;
     PQGVerify    *verify = NULL;
     PRBool passed;
     SECItem hit = { 0, 0, 0 };
     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);
@@ -1297,20 +1300,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: (skipped since we don't use b): b = L -1 - (n*outlen); */
     seedlen = seedBytes * PR_BITS_PER_BYTE;    /* bits in seed */
 step_5:
     /* ******************************************************************
@@ -1373,16 +1383,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
@@ -1492,16 +1507,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);
@@ -1531,53 +1554,100 @@ 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)
+{
+    /* 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, 
@@ -1586,17 +1656,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;
     SECItem pseed_ = {0, 0, 0};
-    HASH_HashType hashtype;
+    HASH_HashType hashtype = HASH_AlgNULL;
     pqgGenType type;
 
 #define CHECKPARAM(cond)      \
     if (!(cond)) {            \
 	*result = SECFailure; \
 	goto cleanup;         \
     }
     if (!params || !vfy || !result) {
