andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: /* andre@0: * PQG parameter generation/verification. Based on FIPS 186-3. andre@0: */ andre@0: #ifdef FREEBL_NO_DEPEND andre@0: #include "stubs.h" andre@0: #endif andre@0: andre@0: #include "prerr.h" andre@0: #include "secerr.h" andre@0: andre@0: #include "prtypes.h" andre@0: #include "blapi.h" andre@0: #include "secitem.h" andre@0: #include "mpi.h" andre@0: #include "mpprime.h" andre@0: #include "mplogic.h" andre@0: #include "secmpi.h" andre@0: andre@0: #define MAX_ITERATIONS 1000 /* Maximum number of iterations of primegen */ andre@0: andre@0: typedef enum { andre@0: FIPS186_1_TYPE, /* Probablistic */ andre@0: FIPS186_3_TYPE, /* Probablistic */ andre@0: FIPS186_3_ST_TYPE /* Shawe-Taylor provable */ andre@0: } pqgGenType; andre@0: andre@0: /* andre@0: * These test iterations are quite a bit larger than we previously had. andre@0: * This is because FIPS 186-3 is worried about the primes in PQG generation. andre@0: * It may be possible to purposefully construct composites which more andre@0: * iterations of Miller-Rabin than the for your normal randomly selected andre@0: * numbers.There are 3 ways to counter this: 1) use one of the cool provably andre@0: * prime algorithms (which would require a lot more work than DSA-2 deservers. andre@0: * 2) add a Lucas primality test (which requires coding a Lucas primality test, andre@0: * or 3) use a larger M-R test count. I chose the latter. It increases the time andre@0: * that it takes to prove the selected prime, but it shouldn't increase the andre@0: * overall time to run the algorithm (non-primes should still faile M-R andre@0: * realively quickly). If you want to get that last bit of performance, andre@0: * implement Lucas and adjust these two functions. See FIPS 186-3 Appendix C andre@0: * and F for more information. andre@0: */ andre@0: int prime_testcount_p(int L, int N) andre@0: { andre@0: switch (L) { andre@0: case 1024: andre@0: return 40; andre@0: case 2048: andre@0: return 56; andre@0: case 3072: andre@0: return 64; andre@0: default: andre@0: break; andre@0: } andre@0: return 50; /* L = 512-960 */ andre@0: } andre@0: andre@0: /* The q numbers are different if you run M-R followd by Lucas. I created andre@0: * a separate function so if someone wanted to add the Lucas check, they andre@0: * could do so fairly easily */ andre@0: int prime_testcount_q(int L, int N) andre@0: { andre@0: return prime_testcount_p(L,N); andre@0: } andre@0: andre@0: /* andre@0: * generic function to make sure our input matches DSA2 requirements andre@0: * this gives us one place to go if we need to bump the requirements in the andre@0: * future. andre@0: */ andre@0: static SECStatus andre@0: pqg_validate_dsa2(unsigned int L, unsigned int N) andre@0: { andre@0: andre@0: switch (L) { andre@0: case 1024: andre@0: if (N != DSA1_Q_BITS) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: break; andre@0: case 2048: andre@0: if ((N != 224) && (N != 256)) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: break; andre@0: case 3072: andre@0: if (N != 256) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: break; andre@0: default: andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: return SECSuccess; andre@0: } andre@0: andre@0: static unsigned int andre@0: pqg_get_default_N(unsigned int L) andre@0: { andre@0: unsigned int N = 0; andre@0: switch (L) { andre@0: case 1024: andre@0: N = DSA1_Q_BITS; andre@0: break; andre@0: case 2048: andre@0: N = 224; andre@0: break; andre@0: case 3072: andre@0: N = 256; andre@0: break; andre@0: default: andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: break; /* N already set to zero */ andre@0: } andre@0: return N; andre@0: } andre@0: andre@0: /* andre@0: * Select the lowest hash algorithm usable andre@0: */ andre@0: static HASH_HashType andre@0: getFirstHash(unsigned int L, unsigned int N) andre@0: { andre@0: if (N < 224) { andre@0: return HASH_AlgSHA1; andre@0: } andre@0: if (N < 256) { andre@0: return HASH_AlgSHA224; andre@0: } andre@0: if (N < 384) { andre@0: return HASH_AlgSHA256; andre@0: } andre@0: if (N < 512) { andre@0: return HASH_AlgSHA384; andre@0: } andre@0: return HASH_AlgSHA512; andre@0: } andre@0: andre@0: /* andre@0: * find the next usable hash algorthim andre@0: */ andre@0: static HASH_HashType andre@0: getNextHash(HASH_HashType hashtype) andre@0: { andre@0: switch (hashtype) { andre@0: case HASH_AlgSHA1: andre@0: hashtype = HASH_AlgSHA224; andre@0: break; andre@0: case HASH_AlgSHA224: andre@0: hashtype = HASH_AlgSHA256; andre@0: break; andre@0: case HASH_AlgSHA256: andre@0: hashtype = HASH_AlgSHA384; andre@0: break; andre@0: case HASH_AlgSHA384: andre@0: hashtype = HASH_AlgSHA512; andre@0: break; andre@0: case HASH_AlgSHA512: andre@0: default: andre@0: hashtype = HASH_AlgTOTAL; andre@0: break; andre@0: } andre@0: return hashtype; andre@0: } andre@0: andre@0: static unsigned int andre@0: HASH_ResultLen(HASH_HashType type) andre@0: { andre@0: const SECHashObject *hash_obj = HASH_GetRawHashObject(type); andre@0: if (hash_obj == NULL) { andre@0: return 0; andre@0: } andre@0: return hash_obj->length; andre@0: } andre@0: andre@0: static SECStatus andre@0: HASH_HashBuf(HASH_HashType type, unsigned char *dest, andre@0: const unsigned char *src, PRUint32 src_len) andre@0: { andre@0: const SECHashObject *hash_obj = HASH_GetRawHashObject(type); andre@0: void *hashcx = NULL; andre@0: unsigned int dummy; andre@0: andre@0: if (hash_obj == NULL) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: hashcx = hash_obj->create(); andre@0: if (hashcx == NULL) { andre@0: return SECFailure; andre@0: } andre@0: hash_obj->begin(hashcx); andre@0: hash_obj->update(hashcx,src,src_len); andre@0: hash_obj->end(hashcx,dest, &dummy, hash_obj->length); andre@0: hash_obj->destroy(hashcx, PR_TRUE); andre@0: return SECSuccess; andre@0: } andre@0: andre@0: unsigned int andre@0: PQG_GetLength(const SECItem *obj) andre@0: { andre@0: unsigned int len = obj->len; andre@0: andre@0: if (obj->data == NULL) { andre@0: return 0; andre@0: } andre@0: if (len > 1 && obj->data[0] == 0) { andre@0: len--; andre@0: } andre@0: return len; andre@0: } andre@0: andre@0: SECStatus andre@0: PQG_Check(const PQGParams *params) andre@0: { andre@0: unsigned int L,N; andre@0: SECStatus rv = SECSuccess; andre@0: andre@0: if (params == NULL) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: andre@0: L = PQG_GetLength(¶ms->prime)*PR_BITS_PER_BYTE; andre@0: N = PQG_GetLength(¶ms->subPrime)*PR_BITS_PER_BYTE; andre@0: andre@0: if (L < 1024) { andre@0: int j; andre@0: andre@0: /* handle DSA1 pqg parameters with less thatn 1024 bits*/ andre@0: if ( N != DSA1_Q_BITS ) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: j = PQG_PBITS_TO_INDEX(L); andre@0: if ( j < 0 ) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: rv = SECFailure; andre@0: } andre@0: } else { andre@0: /* handle DSA2 parameters (includes DSA1, 1024 bits) */ andre@0: rv = pqg_validate_dsa2(L, N); andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: HASH_HashType andre@0: PQG_GetHashType(const PQGParams *params) andre@0: { andre@0: unsigned int L,N; andre@0: andre@0: if (params == NULL) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return HASH_AlgNULL; andre@0: } andre@0: andre@0: L = PQG_GetLength(¶ms->prime)*PR_BITS_PER_BYTE; andre@0: N = PQG_GetLength(¶ms->subPrime)*PR_BITS_PER_BYTE; andre@0: return getFirstHash(L, N); andre@0: } andre@0: andre@0: /* Get a seed for generating P and Q. If in testing mode, copy in the andre@0: ** seed from FIPS 186-1 appendix 5. Otherwise, obtain bytes from the andre@0: ** global random number generator. andre@0: */ andre@0: static SECStatus andre@0: getPQseed(SECItem *seed, PLArenaPool* arena) andre@0: { andre@0: SECStatus rv; andre@0: andre@0: if (!seed->data) { andre@0: seed->data = (unsigned char*)PORT_ArenaZAlloc(arena, seed->len); andre@0: } andre@0: if (!seed->data) { andre@0: PORT_SetError(SEC_ERROR_NO_MEMORY); andre@0: return SECFailure; andre@0: } andre@0: rv = RNG_GenerateGlobalRandomBytes(seed->data, seed->len); andre@0: /* andre@0: * NIST CMVP disallows a sequence of 20 bytes with the most andre@0: * significant byte equal to 0. Perhaps they interpret andre@0: * "a sequence of at least 160 bits" as "a number >= 2^159". andre@0: * So we always set the most significant bit to 1. (bug 334533) andre@0: */ andre@0: seed->data[0] |= 0x80; andre@0: return rv; andre@0: } andre@0: andre@0: /* Generate a candidate h value. If in testing mode, use the h value andre@0: ** specified in FIPS 186-1 appendix 5, h = 2. Otherwise, obtain bytes andre@0: ** from the global random number generator. andre@0: */ andre@0: static SECStatus andre@0: generate_h_candidate(SECItem *hit, mp_int *H) andre@0: { andre@0: SECStatus rv = SECSuccess; andre@0: mp_err err = MP_OKAY; andre@0: #ifdef FIPS_186_1_A5_TEST andre@0: memset(hit->data, 0, hit->len); andre@0: hit->data[hit->len-1] = 0x02; andre@0: #else andre@0: rv = RNG_GenerateGlobalRandomBytes(hit->data, hit->len); andre@0: #endif andre@0: if (rv) andre@0: return SECFailure; andre@0: err = mp_read_unsigned_octets(H, hit->data, hit->len); andre@0: if (err) { andre@0: MP_TO_SEC_ERROR(err); andre@0: return SECFailure; andre@0: } andre@0: return SECSuccess; andre@0: } andre@0: andre@0: static SECStatus andre@0: addToSeed(const SECItem * seed, andre@0: unsigned long addend, andre@0: int seedlen, /* g in 186-1 */ andre@0: SECItem * seedout) andre@0: { andre@0: mp_int s, sum, modulus, tmp; andre@0: mp_err err = MP_OKAY; andre@0: SECStatus rv = SECSuccess; andre@0: MP_DIGITS(&s) = 0; andre@0: MP_DIGITS(&sum) = 0; andre@0: MP_DIGITS(&modulus) = 0; andre@0: MP_DIGITS(&tmp) = 0; andre@0: CHECK_MPI_OK( mp_init(&s) ); andre@0: CHECK_MPI_OK( mp_init(&sum) ); andre@0: CHECK_MPI_OK( mp_init(&modulus) ); andre@0: SECITEM_TO_MPINT(*seed, &s); /* s = seed */ andre@0: /* seed += addend */ andre@0: if (addend < MP_DIGIT_MAX) { andre@0: CHECK_MPI_OK( mp_add_d(&s, (mp_digit)addend, &s) ); andre@0: } else { andre@0: CHECK_MPI_OK( mp_init(&tmp) ); andre@0: CHECK_MPI_OK( mp_set_ulong(&tmp, addend) ); andre@0: CHECK_MPI_OK( mp_add(&s, &tmp, &s) ); andre@0: } andre@0: /*sum = s mod 2**seedlen */ andre@0: CHECK_MPI_OK( mp_div_2d(&s, (mp_digit)seedlen, NULL, &sum) ); andre@0: if (seedout->data != NULL) { andre@0: SECITEM_ZfreeItem(seedout, PR_FALSE); andre@0: } andre@0: MPINT_TO_SECITEM(&sum, seedout, NULL); andre@0: cleanup: andre@0: mp_clear(&s); andre@0: mp_clear(&sum); andre@0: mp_clear(&modulus); andre@0: mp_clear(&tmp); andre@0: if (err) { andre@0: MP_TO_SEC_ERROR(err); andre@0: return SECFailure; andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: /* Compute Hash[(SEED + addend) mod 2**g] andre@0: ** Result is placed in shaOutBuf. andre@0: ** This computation is used in steps 2 and 7 of FIPS 186 Appendix 2.2 and andre@0: ** step 11.2 of FIPS 186-3 Appendix A.1.1.2 . andre@0: */ andre@0: static SECStatus andre@0: addToSeedThenHash(HASH_HashType hashtype, andre@0: const SECItem * seed, andre@0: unsigned long addend, andre@0: int seedlen, /* g in 186-1 */ andre@0: unsigned char * hashOutBuf) andre@0: { andre@0: SECItem str = { 0, 0, 0 }; andre@0: SECStatus rv; andre@0: rv = addToSeed(seed, addend, seedlen, &str); andre@0: if (rv != SECSuccess) { andre@0: return rv; andre@0: } andre@0: rv = HASH_HashBuf(hashtype, hashOutBuf, str.data, str.len);/* hash result */ andre@0: if (str.data) andre@0: SECITEM_ZfreeItem(&str, PR_FALSE); andre@0: return rv; andre@0: } andre@0: andre@0: /* andre@0: ** Perform steps 2 and 3 of FIPS 186-1, appendix 2.2. andre@0: ** Generate Q from seed. andre@0: */ andre@0: static SECStatus andre@0: makeQfromSeed( andre@0: unsigned int g, /* input. Length of seed in bits. */ andre@0: const SECItem * seed, /* input. */ andre@0: mp_int * Q) /* output. */ andre@0: { andre@0: unsigned char sha1[SHA1_LENGTH]; andre@0: unsigned char sha2[SHA1_LENGTH]; andre@0: unsigned char U[SHA1_LENGTH]; andre@0: SECStatus rv = SECSuccess; andre@0: mp_err err = MP_OKAY; andre@0: int i; andre@0: /* ****************************************************************** andre@0: ** Step 2. andre@0: ** "Compute U = SHA[SEED] XOR SHA[(SEED+1) mod 2**g]." andre@0: **/ andre@0: CHECK_SEC_OK( SHA1_HashBuf(sha1, seed->data, seed->len) ); andre@0: CHECK_SEC_OK( addToSeedThenHash(HASH_AlgSHA1, seed, 1, g, sha2) ); andre@0: for (i=0; idata, seed->len) ); andre@0: /* mod 2**N . Step 7 will explicitly set the top bit to 1, so no need andre@0: * to handle mod 2**N-1 */ andre@0: if (hashLen > N_bytes) { andre@0: offset = hashLen - N_bytes; andre@0: } andre@0: /* ****************************************************************** andre@0: ** Step 7. andre@0: ** computed_q = 2**(N-1) + U + 1 - (U mod 2) andre@0: ** andre@0: ** This is the same as: andre@0: ** computed_q = 2**(N-1) | U | 1; andre@0: */ andre@0: U[offset] |= 0x80; /* U is MSB first */ andre@0: U[hashLen-1] |= 0x01; andre@0: err = mp_read_unsigned_octets(Q, &U[offset], N_bytes); andre@0: cleanup: andre@0: memset(U, 0, HASH_LENGTH_MAX); andre@0: if (err) { andre@0: MP_TO_SEC_ERROR(err); andre@0: return SECFailure; andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: /* andre@0: ** Perform steps from FIPS 186-3, Appendix A.1.2.1 and Appendix C.6 andre@0: ** andre@0: ** This generates a provable prime from two smaller prime. The resulting andre@0: ** prime p will have q0 as a multiple of p-1. q0 can be 1. andre@0: ** andre@0: ** This implments steps 4 thorough 22 of FIPS 186-3 A.1.2.1 and andre@0: ** steps 16 through 34 of FIPS 186-2 C.6 andre@0: */ andre@0: #define MAX_ST_SEED_BITS (HASH_LENGTH_MAX*PR_BITS_PER_BYTE) andre@0: SECStatus andre@0: makePrimefromPrimesShaweTaylor( andre@0: HASH_HashType hashtype, /* selected Hashing algorithm */ andre@0: unsigned int length, /* input. Length of prime in bits. */ andre@0: mp_int * c0, /* seed prime */ andre@0: mp_int * q, /* sub prime, can be 1 */ andre@0: mp_int * prime, /* output. */ andre@0: SECItem * prime_seed, /* input/output. */ andre@0: int * prime_gen_counter) /* input/output. */ andre@0: { andre@0: mp_int c; andre@0: mp_int c0_2; andre@0: mp_int t; andre@0: mp_int a; andre@0: mp_int z; andre@0: mp_int two_length_minus_1; andre@0: SECStatus rv = SECFailure; andre@0: int hashlen = HASH_ResultLen(hashtype); andre@0: int outlen = hashlen*PR_BITS_PER_BYTE; andre@0: int offset; andre@0: unsigned char bit, mask; andre@0: /* x needs to hold roundup(L/outlen)*outlen. andre@0: * This can be no larger than L+outlen-1, So we set it's size to andre@0: * our max L + max outlen and know we are safe */ andre@0: unsigned char x[DSA_MAX_P_BITS/8+HASH_LENGTH_MAX]; andre@0: mp_err err = MP_OKAY; andre@0: int i; andre@0: int iterations; andre@0: int old_counter; andre@0: andre@0: MP_DIGITS(&c) = 0; andre@0: MP_DIGITS(&c0_2) = 0; andre@0: MP_DIGITS(&t) = 0; andre@0: MP_DIGITS(&a) = 0; andre@0: MP_DIGITS(&z) = 0; andre@0: MP_DIGITS(&two_length_minus_1) = 0; andre@0: CHECK_MPI_OK( mp_init(&c) ); andre@0: CHECK_MPI_OK( mp_init(&c0_2) ); andre@0: CHECK_MPI_OK( mp_init(&t) ); andre@0: CHECK_MPI_OK( mp_init(&a) ); andre@0: CHECK_MPI_OK( mp_init(&z) ); andre@0: CHECK_MPI_OK( mp_init(&two_length_minus_1) ); andre@0: andre@0: andre@0: /* andre@0: ** There is a slight mapping of variable names depending on which andre@0: ** FIPS 186 steps are being carried out. The mapping is as follows: andre@0: ** variable A.1.2.1 C.6 andre@0: ** c0 p0 c0 andre@0: ** q q 1 andre@0: ** c p c andre@0: ** c0_2 2*p0*q 2*c0 andre@0: ** length L length andre@0: ** prime_seed pseed prime_seed andre@0: ** prime_gen_counter pgen_counter prime_gen_counter andre@0: ** andre@0: ** Also note: or iterations variable is actually iterations+1, since andre@0: ** iterations+1 works better in C. andre@0: */ andre@0: andre@0: /* Step 4/16 iterations = ceiling(length/outlen)-1 */ andre@0: iterations = (length+outlen-1)/outlen; /* NOTE: iterations +1 */ andre@0: /* Step 5/17 old_counter = prime_gen_counter */ andre@0: old_counter = *prime_gen_counter; andre@0: /* andre@0: ** Comment: Generate a pseudorandom integer x in the interval andre@0: ** [2**(lenght-1), 2**length]. andre@0: ** andre@0: ** Step 6/18 x = 0 andre@0: */ andre@0: PORT_Memset(x, 0, sizeof(x)); andre@0: /* andre@0: ** Step 7/19 for i = 0 to iterations do andre@0: ** x = x + (HASH(prime_seed + i) * 2^(i*outlen)) andre@0: */ andre@0: for (i=0; i < iterations; i++) { andre@0: /* is bigger than prime_seed should get to */ andre@0: CHECK_SEC_OK( addToSeedThenHash(hashtype, prime_seed, i, andre@0: MAX_ST_SEED_BITS,&x[(iterations - i - 1)*hashlen])); andre@0: } andre@0: /* Step 8/20 prime_seed = prime_seed + iterations + 1 */ andre@0: CHECK_SEC_OK(addToSeed(prime_seed, iterations, MAX_ST_SEED_BITS, andre@0: prime_seed)); andre@0: /* andre@0: ** Step 9/21 x = 2 ** (length-1) + x mod 2 ** (length-1) andre@0: ** andre@0: ** This step mathematically sets the high bit and clears out andre@0: ** all the other bits higher than length. 'x' is stored andre@0: ** in the x array, MSB first. The above formula gives us an 'x' andre@0: ** which is length bytes long and has the high bit set. We also know andre@0: ** that length <= iterations*outlen since andre@0: ** iterations=ceiling(length/outlen). First we find the offset in andre@0: ** bytes into the array where the high bit is. andre@0: */ andre@0: offset = (outlen*iterations - length)/PR_BITS_PER_BYTE; andre@0: /* now we want to set the 'high bit', since length may not be a andre@0: * multiple of 8,*/ andre@0: bit = 1 << ((length-1) & 0x7); /* select the proper bit in the byte */ andre@0: /* we need to zero out the rest of the bits in the byte above */ andre@0: mask = (bit-1); andre@0: /* now we set it */ andre@0: x[offset] = (mask & x[offset]) | bit; andre@0: /* andre@0: ** Comment: Generate a candidate prime c in the interval andre@0: ** [2**(lenght-1), 2**length]. andre@0: ** andre@0: ** Step 10 t = ceiling(x/(2q(p0))) andre@0: ** Step 22 t = ceiling(x/(2(c0))) andre@0: */ andre@0: CHECK_MPI_OK( mp_read_unsigned_octets(&t, &x[offset], andre@0: hashlen*iterations - offset ) ); /* t = x */ andre@0: CHECK_MPI_OK( mp_mul(c0, q, &c0_2) ); /* c0_2 is now c0*q */ andre@0: CHECK_MPI_OK( mp_add(&c0_2, &c0_2, &c0_2) ); /* c0_2 is now 2*q*c0 */ andre@0: CHECK_MPI_OK( mp_add(&t, &c0_2, &t) ); /* t = x+2*q*c0 */ andre@0: CHECK_MPI_OK( mp_sub_d(&t, (mp_digit) 1, &t) ); /* t = x+2*q*c0 -1 */ andre@0: /* t = floor((x+2qc0-1)/2qc0) = ceil(x/2qc0) */ andre@0: CHECK_MPI_OK( mp_div(&t, &c0_2, &t, NULL) ); andre@0: /* andre@0: ** step 11: if (2tqp0 +1 > 2**length), then t = ceiling(2**(length-1)/2qp0) andre@0: ** step 12: t = 2tqp0 +1. andre@0: ** andre@0: ** step 23: if (2tc0 +1 > 2**length), then t = ceiling(2**(length-1)/2c0) andre@0: ** step 24: t = 2tc0 +1. andre@0: */ andre@0: CHECK_MPI_OK( mp_2expt(&two_length_minus_1, length-1) ); andre@0: step_23: andre@0: CHECK_MPI_OK( mp_mul(&t, &c0_2, &c) ); /* c = t*2qc0 */ andre@0: CHECK_MPI_OK( mp_add_d(&c, (mp_digit)1, &c) ); /* c= 2tqc0 + 1*/ andre@0: if (mpl_significant_bits(&c) > length) { /* if c > 2**length */ andre@0: CHECK_MPI_OK( mp_sub_d(&c0_2, (mp_digit) 1, &t) ); /* t = 2qc0-1 */ andre@0: /* t = 2**(length-1) + 2qc0 -1 */ andre@0: CHECK_MPI_OK( mp_add(&two_length_minus_1,&t, &t) ); andre@0: /* t = floor((2**(length-1)+2qc0 -1)/2qco) andre@0: * = ceil(2**(lenght-2)/2qc0) */ andre@0: CHECK_MPI_OK( mp_div(&t, &c0_2, &t, NULL) ); andre@0: CHECK_MPI_OK( mp_mul(&t, &c0_2, &c) ); andre@0: CHECK_MPI_OK( mp_add_d(&c, (mp_digit)1, &c) ); /* c= 2tqc0 + 1*/ andre@0: } andre@0: /* Step 13/25 prime_gen_counter = prime_gen_counter + 1*/ andre@0: (*prime_gen_counter)++; andre@0: /* andre@0: ** Comment: Test the candidate prime c for primality; first pick an andre@0: ** integer a between 2 and c-2. andre@0: ** andre@0: ** Step 14/26 a=0 andre@0: */ andre@0: PORT_Memset(x, 0, sizeof(x)); /* use x for a */ andre@0: /* andre@0: ** Step 15/27 for i = 0 to iterations do andre@0: ** a = a + (HASH(prime_seed + i) * 2^(i*outlen)) andre@0: ** andre@0: ** NOTE: we reuse the x array for 'a' initially. andre@0: */ andre@0: for (i=0; i < iterations; i++) { andre@0: /* MAX_ST_SEED_BITS is bigger than prime_seed should get to */ andre@0: CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, i, andre@0: MAX_ST_SEED_BITS,&x[(iterations - i - 1)*hashlen])); andre@0: } andre@0: /* Step 16/28 prime_seed = prime_seed + iterations + 1 */ andre@0: CHECK_SEC_OK(addToSeed(prime_seed, iterations, MAX_ST_SEED_BITS, andre@0: prime_seed)); andre@0: /* Step 17/29 a = 2 + (a mod (c-3)). */ andre@0: CHECK_MPI_OK( mp_read_unsigned_octets(&a, x, iterations*hashlen) ); andre@0: CHECK_MPI_OK( mp_sub_d(&c, (mp_digit) 3, &z) ); /* z = c -3 */ andre@0: CHECK_MPI_OK( mp_mod(&a, &z, &a) ); /* a = a mod c -3 */ andre@0: CHECK_MPI_OK( mp_add_d(&a, (mp_digit) 2, &a) ); /* a = 2 + a mod c -3 */ andre@0: /* andre@0: ** Step 18 z = a**(2tq) mod p. andre@0: ** Step 30 z = a**(2t) mod c. andre@0: */ andre@0: CHECK_MPI_OK( mp_mul(&t, q, &z) ); /* z = tq */ andre@0: CHECK_MPI_OK( mp_add(&z, &z, &z) ); /* z = 2tq */ andre@0: CHECK_MPI_OK( mp_exptmod(&a, &z, &c, &z) ); /* z = a**(2tq) mod c */ andre@0: /* andre@0: ** Step 19 if (( 1 == GCD(z-1,p)) and ( 1 == z**p0 mod p )), then andre@0: ** Step 31 if (( 1 == GCD(z-1,c)) and ( 1 == z**c0 mod c )), then andre@0: */ andre@0: CHECK_MPI_OK( mp_sub_d(&z, (mp_digit) 1, &a) ); andre@0: CHECK_MPI_OK( mp_gcd(&a,&c,&a )); andre@0: if (mp_cmp_d(&a, (mp_digit)1) == 0) { andre@0: CHECK_MPI_OK( mp_exptmod(&z, c0, &c, &a) ); andre@0: if (mp_cmp_d(&a, (mp_digit)1) == 0) { andre@0: /* Step 31.1 prime = c */ andre@0: CHECK_MPI_OK( mp_copy(&c, prime) ); andre@0: /* andre@0: ** Step 31.2 return Success, prime, prime_seed, andre@0: ** prime_gen_counter andre@0: */ andre@0: rv = SECSuccess; andre@0: goto cleanup; andre@0: } andre@0: } andre@0: /* andre@0: ** Step 20/32 If (prime_gen_counter > 4 * length + old_counter then andre@0: ** return (FAILURE, 0, 0, 0). andre@0: ** NOTE: the test is reversed, so we fall through on failure to the andre@0: ** cleanup routine andre@0: */ andre@0: if (*prime_gen_counter < (4*length + old_counter)) { andre@0: /* Step 21/33 t = t + 1 */ andre@0: CHECK_MPI_OK( mp_add_d(&t, (mp_digit) 1, &t) ); andre@0: /* Step 22/34 Go to step 23/11 */ andre@0: goto step_23; andre@0: } andre@0: andre@0: /* if (prime_gencont > (4*length + old_counter), fall through to failure */ andre@0: rv = SECFailure; /* really is already set, but paranoia is good */ andre@0: andre@0: cleanup: andre@0: mp_clear(&c); andre@0: mp_clear(&c0_2); andre@0: mp_clear(&t); andre@0: mp_clear(&a); andre@0: mp_clear(&z); andre@0: mp_clear(&two_length_minus_1); andre@0: if (err) { andre@0: MP_TO_SEC_ERROR(err); andre@0: rv = SECFailure; andre@0: } andre@0: if (rv == SECFailure) { andre@0: mp_zero(prime); andre@0: if (prime_seed->data) { andre@0: SECITEM_FreeItem(prime_seed, PR_FALSE); andre@0: } andre@0: *prime_gen_counter = 0; andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: /* andre@0: ** Perform steps from FIPS 186-3, Appendix C.6 andre@0: ** andre@0: ** This generates a provable prime from a seed andre@0: */ andre@0: SECStatus andre@0: makePrimefromSeedShaweTaylor( andre@0: HASH_HashType hashtype, /* selected Hashing algorithm */ andre@0: unsigned int length, /* input. Length of prime in bits. */ andre@0: const SECItem * input_seed, /* input. */ andre@0: mp_int * prime, /* output. */ andre@0: SECItem * prime_seed, /* output. */ andre@0: int * prime_gen_counter) /* output. */ andre@0: { andre@0: mp_int c; andre@0: mp_int c0; andre@0: mp_int one; andre@0: SECStatus rv = SECFailure; andre@0: int hashlen = HASH_ResultLen(hashtype); andre@0: int outlen = hashlen*PR_BITS_PER_BYTE; andre@0: int offset; andre@0: unsigned char bit, mask; andre@0: unsigned char x[HASH_LENGTH_MAX*2]; andre@0: mp_digit dummy; andre@0: mp_err err = MP_OKAY; andre@0: int i; andre@0: andre@0: MP_DIGITS(&c) = 0; andre@0: MP_DIGITS(&c0) = 0; andre@0: MP_DIGITS(&one) = 0; andre@0: CHECK_MPI_OK( mp_init(&c) ); andre@0: CHECK_MPI_OK( mp_init(&c0) ); andre@0: CHECK_MPI_OK( mp_init(&one) ); andre@0: andre@0: /* Step 1. if length < 2 then return (FAILURE, 0, 0, 0) */ andre@0: if (length < 2) { andre@0: rv = SECFailure; andre@0: goto cleanup; andre@0: } andre@0: /* Step 2. if length >= 33 then goto step 14 */ andre@0: if (length >= 33) { andre@0: mp_zero(&one); andre@0: CHECK_MPI_OK( mp_add_d(&one, (mp_digit) 1, &one) ); andre@0: andre@0: /* Step 14 (status, c0, prime_seed, prime_gen_counter) = andre@0: ** (ST_Random_Prime((ceil(length/2)+1, input_seed) andre@0: */ andre@0: rv = makePrimefromSeedShaweTaylor(hashtype, (length+1)/2+1, andre@0: input_seed, &c0, prime_seed, prime_gen_counter); andre@0: /* Step 15 if FAILURE is returned, return (FAILURE, 0, 0, 0). */ andre@0: if (rv != SECSuccess) { andre@0: goto cleanup; andre@0: } andre@0: /* Steps 16-34 */ andre@0: rv = makePrimefromPrimesShaweTaylor(hashtype,length, &c0, &one, andre@0: prime, prime_seed, prime_gen_counter); andre@0: goto cleanup; /* we're done, one way or the other */ andre@0: } andre@0: /* Step 3 prime_seed = input_seed */ andre@0: CHECK_SEC_OK(SECITEM_CopyItem(NULL, prime_seed, input_seed)); andre@0: /* Step 4 prime_gen_count = 0 */ andre@0: *prime_gen_counter = 0; andre@0: andre@0: step_5: andre@0: /* Step 5 c = Hash(prime_seed) xor Hash(prime_seed+1). */ andre@0: CHECK_SEC_OK(HASH_HashBuf(hashtype, x, prime_seed->data, prime_seed->len) ); andre@0: CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, 1, andre@0: MAX_ST_SEED_BITS, &x[hashlen]) ); andre@0: for (i=0; i < hashlen; i++) { andre@0: x[i] = x[i] ^ x[i+hashlen]; andre@0: } andre@0: /* Step 6 c = 2**length-1 + c mod 2**length-1 */ andre@0: /* This step mathematically sets the high bit and clears out andre@0: ** all the other bits higher than length. Right now c is stored andre@0: ** in the x array, MSB first. The above formula gives us a c which andre@0: ** is length bytes long and has the high bit set. We also know that andre@0: ** length < outlen since the smallest outlen is 160 bits and the largest andre@0: ** length at this point is 32 bits. So first we find the offset in bytes andre@0: ** into the array where the high bit is. andre@0: */ andre@0: offset = (outlen - length)/PR_BITS_PER_BYTE; andre@0: /* now we want to set the 'high bit'. We have to calculate this since andre@0: * length may not be a multiple of 8.*/ andre@0: bit = 1 << ((length-1) & 0x7); /* select the proper bit in the byte */ andre@0: /* we need to zero out the rest of the bits in the byte above */ andre@0: mask = (bit-1); andre@0: /* now we set it */ andre@0: x[offset] = (mask & x[offset]) | bit; andre@0: /* Step 7 c = c*floor(c/2) + 1 */ andre@0: /* set the low bit. much easier to find (the end of the array) */ andre@0: x[hashlen-1] |= 1; andre@0: /* now that we've set our bits, we can create our candidate "c" */ andre@0: CHECK_MPI_OK( mp_read_unsigned_octets(&c, &x[offset], hashlen-offset) ); andre@0: /* Step 8 prime_gen_counter = prime_gen_counter + 1 */ andre@0: (*prime_gen_counter)++; andre@0: /* Step 9 prime_seed = prime_seed + 2 */ andre@0: CHECK_SEC_OK(addToSeed(prime_seed, 2, MAX_ST_SEED_BITS, prime_seed)); andre@0: /* Step 10 Perform deterministic primality test on c. For example, since andre@0: ** c is small, it's primality can be tested by trial division, See andre@0: ** See Appendic C.7. andre@0: ** andre@0: ** We in fact test with trial division. mpi has a built int trial divider andre@0: ** that divides all divisors up to 2^16. andre@0: */ andre@0: if (prime_tab[prime_tab_size-1] < 0xFFF1) { andre@0: /* we aren't testing all the primes between 0 and 2^16, we really andre@0: * can't use this construction. Just fail. */ andre@0: rv = SECFailure; andre@0: goto cleanup; andre@0: } andre@0: dummy = prime_tab_size; andre@0: err = mpp_divis_primes(&c, &dummy); andre@0: /* Step 11 if c is prime then */ andre@0: if (err == MP_NO) { andre@0: /* Step 11.1 prime = c */ andre@0: CHECK_MPI_OK( mp_copy(&c, prime) ); andre@0: /* Step 11.2 return SUCCESS prime, prime_seed, prime_gen_counter */ andre@0: err = MP_OKAY; andre@0: rv = SECSuccess; andre@0: goto cleanup; andre@0: } else if (err != MP_YES) { andre@0: goto cleanup; /* function failed, bail out */ andre@0: } else { andre@0: /* reset mp_err */ andre@0: err = MP_OKAY; andre@0: } andre@0: /* andre@0: ** Step 12 if (prime_gen_counter > (4*len)) andre@0: ** then return (FAILURE, 0, 0, 0)) andre@0: ** Step 13 goto step 5 andre@0: */ andre@0: if (*prime_gen_counter <= (4*length)) { andre@0: goto step_5; andre@0: } andre@0: /* if (prime_gencont > 4*length), fall through to failure */ andre@0: rv = SECFailure; /* really is already set, but paranoia is good */ andre@0: andre@0: cleanup: andre@0: mp_clear(&c); andre@0: mp_clear(&c0); andre@0: mp_clear(&one); andre@0: if (err) { andre@0: MP_TO_SEC_ERROR(err); andre@0: rv = SECFailure; andre@0: } andre@0: if (rv == SECFailure) { andre@0: mp_zero(prime); andre@0: if (prime_seed->data) { andre@0: SECITEM_FreeItem(prime_seed, PR_FALSE); andre@0: } andre@0: *prime_gen_counter = 0; andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: andre@0: /* andre@0: * Find a Q and algorithm from Seed. andre@0: */ andre@0: static SECStatus andre@0: findQfromSeed( andre@0: unsigned int L, /* input. Length of p in bits. */ andre@0: unsigned int N, /* input. Length of q in bits. */ andre@0: unsigned int g, /* input. Length of seed in bits. */ andre@0: const SECItem * seed, /* input. */ andre@0: mp_int * Q, /* input. */ andre@0: mp_int * Q_, /* output. */ andre@0: int * qseed_len, /* output */ andre@0: HASH_HashType *hashtypePtr, /* output. Hash uses */ andre@0: pqgGenType *typePtr) /* output. Generation Type used */ andre@0: { andre@0: HASH_HashType hashtype; andre@0: SECItem firstseed = { 0, 0, 0 }; andre@0: SECItem qseed = { 0, 0, 0 }; andre@0: SECStatus rv; andre@0: andre@0: *qseed_len = 0; /* only set if FIPS186_3_ST_TYPE */ andre@0: andre@0: /* handle legacy small DSA first can only be FIPS186_1_TYPE */ andre@0: if (L < 1024) { andre@0: rv =makeQfromSeed(g,seed,Q_); andre@0: if ((rv == SECSuccess) && (mp_cmp(Q,Q_) == 0)) { andre@0: *hashtypePtr = HASH_AlgSHA1; andre@0: *typePtr = FIPS186_1_TYPE; andre@0: return SECSuccess; andre@0: } andre@0: return SECFailure; andre@0: } andre@0: /* 1024 could use FIPS186_1 or FIPS186_3 algorithms, we need to try andre@0: * them both */ andre@0: if (L == 1024) { andre@0: rv = makeQfromSeed(g,seed,Q_); andre@0: if (rv == SECSuccess) { andre@0: if (mp_cmp(Q,Q_) == 0) { andre@0: *hashtypePtr = HASH_AlgSHA1; andre@0: *typePtr = FIPS186_1_TYPE; andre@0: return SECSuccess; andre@0: } andre@0: } andre@0: /* fall through for FIPS186_3 types */ andre@0: } andre@0: /* at this point we know we aren't using FIPS186_1, start trying FIPS186_3 andre@0: * with appropriate hash types */ andre@0: for (hashtype = getFirstHash(L,N); hashtype != HASH_AlgTOTAL; andre@0: hashtype=getNextHash(hashtype)) { andre@0: rv = makeQ2fromSeed(hashtype, N, seed, Q_); andre@0: if (rv != SECSuccess) { andre@0: continue; andre@0: } andre@0: if (mp_cmp(Q,Q_) == 0) { andre@0: *hashtypePtr = hashtype; andre@0: *typePtr = FIPS186_3_TYPE; andre@0: return SECSuccess; andre@0: } andre@0: } andre@0: /* andre@0: * OK finally try FIPS186_3 Shawe-Taylor andre@0: */ andre@0: firstseed = *seed; andre@0: firstseed.len = seed->len/3; andre@0: for (hashtype = getFirstHash(L,N); hashtype != HASH_AlgTOTAL; andre@0: hashtype=getNextHash(hashtype)) { andre@0: int count; andre@0: andre@0: rv = makePrimefromSeedShaweTaylor(hashtype, N, &firstseed, Q_, andre@0: &qseed, &count); andre@0: if (rv != SECSuccess) { andre@0: continue; andre@0: } andre@0: if (mp_cmp(Q,Q_) == 0) { andre@0: /* check qseed as well... */ andre@0: int offset = seed->len - qseed.len; andre@0: if ((offset < 0) || andre@0: (PORT_Memcmp(&seed->data[offset],qseed.data,qseed.len) != 0)) { andre@0: /* we found q, but the seeds don't match. This isn't an andre@0: * accident, someone has been tweeking with the seeds, just andre@0: * fail a this point. */ andre@0: SECITEM_FreeItem(&qseed,PR_FALSE); andre@0: return SECFailure; andre@0: } andre@0: *qseed_len = qseed.len; andre@0: *hashtypePtr = hashtype; andre@0: *typePtr = FIPS186_3_ST_TYPE; andre@0: SECITEM_FreeItem(&qseed, PR_FALSE); andre@0: return SECSuccess; andre@0: } andre@0: SECITEM_FreeItem(&qseed, PR_FALSE); andre@0: } andre@0: /* no hash algorithms found which match seed to Q, fail */ andre@0: return SECFailure; andre@0: } andre@0: andre@0: andre@0: andre@0: /* andre@0: ** Perform steps 7, 8 and 9 of FIPS 186, appendix 2.2. andre@0: ** which are the same as steps 11.1-11.5 of FIPS 186-2, App A.1.1.2 andre@0: ** Generate P from Q, seed, L, and offset. andre@0: */ andre@0: static SECStatus andre@0: makePfromQandSeed( andre@0: HASH_HashType hashtype, /* selected Hashing algorithm */ andre@0: unsigned int L, /* Length of P in bits. Per FIPS 186. */ andre@0: unsigned int N, /* Length of Q in bits. Per FIPS 186. */ andre@0: unsigned int offset, /* Per FIPS 186, App 2.2. & 186-3 App A.1.1.2 */ andre@0: unsigned int seedlen, /* input. Length of seed in bits. (g in 186-1)*/ andre@0: const SECItem * seed, /* input. */ andre@0: const mp_int * Q, /* input. */ andre@0: mp_int * P) /* output. */ andre@0: { andre@0: unsigned int j; /* Per FIPS 186-3 App. A.1.1.2 (k in 186-1)*/ andre@0: unsigned int n; /* Per FIPS 186, appendix 2.2. */ andre@0: mp_digit b; /* Per FIPS 186, appendix 2.2. */ andre@0: unsigned int outlen; /* Per FIPS 186-3 App. A.1.1.2 */ andre@0: unsigned int hashlen; /* outlen in bytes */ andre@0: unsigned char V_j[HASH_LENGTH_MAX]; andre@0: mp_int W, X, c, twoQ, V_n, tmp; andre@0: mp_err err = MP_OKAY; andre@0: SECStatus rv = SECSuccess; andre@0: /* Initialize bignums */ andre@0: MP_DIGITS(&W) = 0; andre@0: MP_DIGITS(&X) = 0; andre@0: MP_DIGITS(&c) = 0; andre@0: MP_DIGITS(&twoQ) = 0; andre@0: MP_DIGITS(&V_n) = 0; andre@0: MP_DIGITS(&tmp) = 0; andre@0: CHECK_MPI_OK( mp_init(&W) ); andre@0: CHECK_MPI_OK( mp_init(&X) ); andre@0: CHECK_MPI_OK( mp_init(&c) ); andre@0: CHECK_MPI_OK( mp_init(&twoQ) ); andre@0: CHECK_MPI_OK( mp_init(&tmp) ); andre@0: CHECK_MPI_OK( mp_init(&V_n) ); andre@0: andre@0: hashlen = HASH_ResultLen(hashtype); andre@0: outlen = hashlen*PR_BITS_PER_BYTE; andre@0: andre@0: /* L - 1 = n*outlen + b */ andre@0: n = (L - 1) / outlen; andre@0: b = (L - 1) % outlen; andre@0: andre@0: /* ****************************************************************** andre@0: ** Step 11.1 (Step 7 in 186-1) andre@0: ** "for j = 0 ... n let andre@0: ** V_j = SHA[(SEED + offset + j) mod 2**seedlen]." andre@0: ** andre@0: ** Step 11.2 (Step 8 in 186-1) andre@0: ** "W = V_0 + (V_1 * 2**outlen) + ... + (V_n-1 * 2**((n-1)*outlen)) andre@0: ** + ((V_n mod 2**b) * 2**(n*outlen)) andre@0: */ andre@0: for (j=0; j= 0) /* H >= P-1 */ andre@0: CHECK_MPI_OK( mp_sub(H, &pm1, H) ); /* H = H mod (P-1) */ andre@0: /* Let b = 2**n (smallest power of 2 greater than P). andre@0: ** Since P-1 >= b/2, and H < b, quotient(H/(P-1)) = 0 or 1 andre@0: ** so the above operation safely computes H mod (P-1) andre@0: */ andre@0: /* Check for H = to 0 or 1. Regen H if so. (Regen means return error). */ andre@0: if (mp_cmp_d(H, 1) <= 0) { andre@0: rv = SECFailure; andre@0: goto cleanup; andre@0: } andre@0: /* Compute G, according to the equation G = (H ** ((P-1)/Q)) mod P */ andre@0: CHECK_MPI_OK( mp_div(&pm1, Q, &exp, NULL) ); /* exp = (P-1)/Q */ andre@0: CHECK_MPI_OK( mp_exptmod(H, &exp, P, G) ); /* G = H ** exp mod P */ andre@0: /* Check for G == 0 or G == 1, return error if so. */ andre@0: if (mp_cmp_d(G, 1) <= 0) { andre@0: rv = SECFailure; andre@0: goto cleanup; andre@0: } andre@0: *passed = PR_TRUE; andre@0: cleanup: andre@0: mp_clear(&exp); andre@0: mp_clear(&pm1); andre@0: if (err) { andre@0: MP_TO_SEC_ERROR(err); andre@0: rv = SECFailure; andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: /* andre@0: ** Generate G from seed, index, P, and Q. andre@0: */ andre@0: static SECStatus andre@0: makeGfromIndex(HASH_HashType hashtype, andre@0: const mp_int *P, /* input. */ andre@0: const mp_int *Q, /* input. */ andre@0: const SECItem *seed, /* input. */ andre@0: unsigned char index, /* input. */ andre@0: mp_int *G) /* input/output */ andre@0: { andre@0: mp_int e, pm1, W; andre@0: unsigned int count; andre@0: unsigned char data[HASH_LENGTH_MAX]; andre@0: unsigned int len; andre@0: mp_err err = MP_OKAY; andre@0: SECStatus rv = SECSuccess; andre@0: const SECHashObject *hashobj; andre@0: void *hashcx = NULL; andre@0: andre@0: MP_DIGITS(&e) = 0; andre@0: MP_DIGITS(&pm1) = 0; andre@0: MP_DIGITS(&W) = 0; andre@0: CHECK_MPI_OK( mp_init(&e) ); andre@0: CHECK_MPI_OK( mp_init(&pm1) ); andre@0: CHECK_MPI_OK( mp_init(&W) ); andre@0: andre@0: /* initialize our hash stuff */ andre@0: hashobj = HASH_GetRawHashObject(hashtype); andre@0: if (hashobj == NULL) { andre@0: /* shouldn't happen */ andre@0: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); andre@0: rv = SECFailure; andre@0: goto cleanup; andre@0: } andre@0: hashcx = hashobj->create(); andre@0: if (hashcx == NULL) { andre@0: rv = SECFailure; andre@0: goto cleanup; andre@0: } andre@0: andre@0: CHECK_MPI_OK( mp_sub_d(P, 1, &pm1) ); /* P - 1 */ andre@0: /* Step 3 e = (p-1)/q */ andre@0: CHECK_MPI_OK( mp_div(&pm1, Q, &e, NULL) ); /* e = (P-1)/Q */ andre@0: /* Steps 4, 5, and 6 */ andre@0: /* count is a 16 bit value in the spec. We actually represent count andre@0: * as more than 16 bits so we can easily detect the 16 bit overflow */ andre@0: #define MAX_COUNT 0x10000 andre@0: for (count = 1; count < MAX_COUNT; count++) { andre@0: /* step 7 andre@0: * U = domain_param_seed || "ggen" || index || count andre@0: * step 8 andre@0: * W = HASH(U) andre@0: */ andre@0: hashobj->begin(hashcx); andre@0: hashobj->update(hashcx,seed->data,seed->len); andre@0: hashobj->update(hashcx, (unsigned char *)"ggen", 4); andre@0: hashobj->update(hashcx,&index, 1); andre@0: data[0] = (count >> 8) & 0xff; andre@0: data[1] = count & 0xff; andre@0: hashobj->update(hashcx, data, 2); andre@0: hashobj->end(hashcx, data, &len, sizeof(data)); andre@0: OCTETS_TO_MPINT(data, &W, len); andre@0: /* step 9. g = W**e mod p */ andre@0: CHECK_MPI_OK( mp_exptmod(&W, &e, P, G) ); andre@0: /* step 10. if (g < 2) then goto step 5 */ andre@0: /* NOTE: this weird construct is to keep the flow according to the spec. andre@0: * the continue puts us back to step 5 of the for loop */ andre@0: if (mp_cmp_d(G, 2) < 0) { andre@0: continue; andre@0: } andre@0: break; /* step 11 follows step 10 if the test condition is false */ andre@0: } andre@0: if (count >= MAX_COUNT) { andre@0: rv = SECFailure; /* last part of step 6 */ andre@0: } andre@0: /* step 11. andre@0: * return valid G */ andre@0: cleanup: andre@0: PORT_Memset(data, 0, sizeof(data)); andre@0: if (hashcx) { andre@0: hashobj->destroy(hashcx, PR_TRUE); andre@0: } andre@0: mp_clear(&e); andre@0: mp_clear(&pm1); andre@0: mp_clear(&W); andre@0: if (err) { andre@0: MP_TO_SEC_ERROR(err); andre@0: rv = SECFailure; andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: /* This code uses labels and gotos, so that it can follow the numbered andre@0: ** steps in the algorithms from FIPS 186-3 appendix A.1.1.2 very closely, andre@0: ** and so that the correctness of this code can be easily verified. andre@0: ** So, please forgive the ugly c code. andre@0: **/ andre@0: static SECStatus andre@0: pqg_ParamGen(unsigned int L, unsigned int N, pqgGenType type, andre@0: unsigned int seedBytes, PQGParams **pParams, PQGVerify **pVfy) andre@0: { andre@0: unsigned int n; /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */ andre@0: unsigned int b; /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */ andre@0: unsigned int seedlen; /* Per FIPS 186-3 app A.1.1.2 (was 'g' 186-1)*/ andre@0: unsigned int counter; /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */ andre@0: unsigned int offset; /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */ andre@0: unsigned int outlen; /* Per FIPS 186-3, appendix A.1.1.2. */ andre@0: unsigned int maxCount; andre@0: HASH_HashType hashtype; andre@0: SECItem *seed; /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */ andre@0: PLArenaPool *arena = NULL; andre@0: PQGParams *params = NULL; andre@0: PQGVerify *verify = NULL; andre@0: PRBool passed; andre@0: SECItem hit = { 0, 0, 0 }; andre@0: SECItem firstseed = { 0, 0, 0 }; andre@0: SECItem qseed = { 0, 0, 0 }; andre@0: SECItem pseed = { 0, 0, 0 }; andre@0: mp_int P, Q, G, H, l, p0; andre@0: mp_err err = MP_OKAY; andre@0: SECStatus rv = SECFailure; andre@0: int iterations = 0; andre@0: andre@0: andre@0: /* Step 1. L and N already checked by caller*/ andre@0: /* Step 2. if (seedlen < N) return INVALID; */ andre@0: if (seedBytes < N/PR_BITS_PER_BYTE || !pParams || !pVfy) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: /* Initialize an arena for the params. */ andre@0: arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); andre@0: if (!arena) { andre@0: PORT_SetError(SEC_ERROR_NO_MEMORY); andre@0: return SECFailure; andre@0: } andre@0: params = (PQGParams *)PORT_ArenaZAlloc(arena, sizeof(PQGParams)); andre@0: if (!params) { andre@0: PORT_SetError(SEC_ERROR_NO_MEMORY); andre@0: PORT_FreeArena(arena, PR_TRUE); andre@0: return SECFailure; andre@0: } andre@0: params->arena = arena; andre@0: /* Initialize an arena for the verify. */ andre@0: arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); andre@0: if (!arena) { andre@0: PORT_SetError(SEC_ERROR_NO_MEMORY); andre@0: PORT_FreeArena(params->arena, PR_TRUE); andre@0: return SECFailure; andre@0: } andre@0: verify = (PQGVerify *)PORT_ArenaZAlloc(arena, sizeof(PQGVerify)); andre@0: if (!verify) { andre@0: PORT_SetError(SEC_ERROR_NO_MEMORY); andre@0: PORT_FreeArena(arena, PR_TRUE); andre@0: PORT_FreeArena(params->arena, PR_TRUE); andre@0: return SECFailure; andre@0: } andre@0: verify->arena = arena; andre@0: seed = &verify->seed; andre@0: arena = NULL; andre@0: /* Initialize bignums */ andre@0: MP_DIGITS(&P) = 0; andre@0: MP_DIGITS(&Q) = 0; andre@0: MP_DIGITS(&G) = 0; andre@0: MP_DIGITS(&H) = 0; andre@0: MP_DIGITS(&l) = 0; andre@0: MP_DIGITS(&p0) = 0; andre@0: CHECK_MPI_OK( mp_init(&P) ); andre@0: CHECK_MPI_OK( mp_init(&Q) ); andre@0: CHECK_MPI_OK( mp_init(&G) ); andre@0: CHECK_MPI_OK( mp_init(&H) ); andre@0: CHECK_MPI_OK( mp_init(&l) ); andre@0: CHECK_MPI_OK( mp_init(&p0) ); andre@0: andre@0: /* Select Hash and Compute lengths. */ andre@0: /* getFirstHash gives us the smallest acceptable hash for this key andre@0: * strength */ andre@0: hashtype = getFirstHash(L,N); andre@0: outlen = HASH_ResultLen(hashtype)*PR_BITS_PER_BYTE; andre@0: andre@0: /* Step 3: n = Ceil(L/outlen)-1; (same as n = Floor((L-1)/outlen)) */ andre@0: n = (L - 1) / outlen; andre@0: /* Step 4: b = L -1 - (n*outlen); (same as n = (L-1) mod outlen) */ andre@0: b = (L - 1) % outlen; andre@0: seedlen = seedBytes * PR_BITS_PER_BYTE; /* bits in seed */ andre@0: step_5: andre@0: /* ****************************************************************** andre@0: ** Step 5. (Step 1 in 186-1) andre@0: ** "Choose an abitrary sequence of at least N bits and call it SEED. andre@0: ** Let g be the length of SEED in bits." andre@0: */ andre@0: if (++iterations > MAX_ITERATIONS) { /* give up after a while */ andre@0: PORT_SetError(SEC_ERROR_NEED_RANDOM); andre@0: goto cleanup; andre@0: } andre@0: seed->len = seedBytes; andre@0: CHECK_SEC_OK( getPQseed(seed, verify->arena) ); andre@0: /* ****************************************************************** andre@0: ** Step 6. (Step 2 in 186-1) andre@0: ** andre@0: ** "Compute U = SHA[SEED] XOR SHA[(SEED+1) mod 2**g]. (186-1)" andre@0: ** "Compute U = HASH[SEED] 2**(N-1). (186-3)" andre@0: ** andre@0: ** Step 7. (Step 3 in 186-1) andre@0: ** "Form Q from U by setting the most signficant bit (the 2**159 bit) andre@0: ** and the least signficant bit to 1. In terms of boolean operations, andre@0: ** Q = U OR 2**159 OR 1. Note that 2**159 < Q < 2**160. (186-1)" andre@0: ** andre@0: ** "q = 2**(N-1) + U + 1 - (U mod 2) (186-3) andre@0: ** andre@0: ** Note: Both formulations are the same for U < 2**(N-1) and N=160 andre@0: ** andre@0: ** If using Shawe-Taylor, We do the entire A.1.2.1.2 setps in the block andre@0: ** FIPS186_3_ST_TYPE. andre@0: */ andre@0: if (type == FIPS186_1_TYPE) { andre@0: CHECK_SEC_OK( makeQfromSeed(seedlen, seed, &Q) ); andre@0: } else if (type == FIPS186_3_TYPE) { andre@0: CHECK_SEC_OK( makeQ2fromSeed(hashtype, N, seed, &Q) ); andre@0: } else { andre@0: /* FIPS186_3_ST_TYPE */ andre@0: int qgen_counter, pgen_counter; andre@0: andre@0: /* Step 1 (L,N) already checked for acceptability */ andre@0: andre@0: firstseed = *seed; andre@0: qgen_counter = 0; andre@0: /* Step 2. Use N and firstseed to generate random prime q andre@0: * using Apendix C.6 */ andre@0: CHECK_SEC_OK( makePrimefromSeedShaweTaylor(hashtype, N, &firstseed, &Q, andre@0: &qseed, &qgen_counter) ); andre@0: /* Step 3. Use floor(L/2+1) and qseed to generate random prime p0 andre@0: * using Appendix C.6 */ andre@0: pgen_counter = 0; andre@0: CHECK_SEC_OK( makePrimefromSeedShaweTaylor(hashtype, (L+1)/2+1, andre@0: &qseed, &p0, &pseed, &pgen_counter) ); andre@0: /* Steps 4-22 FIPS 186-3 appendix A.1.2.1.2 */ andre@0: CHECK_SEC_OK( makePrimefromPrimesShaweTaylor(hashtype, L, andre@0: &p0, &Q, &P, &pseed, &pgen_counter) ); andre@0: andre@0: /* combine all the seeds */ andre@0: seed->len = firstseed.len +qseed.len + pseed.len; andre@0: seed->data = PORT_ArenaZAlloc(verify->arena, seed->len); andre@0: if (seed->data == NULL) { andre@0: goto cleanup; andre@0: } andre@0: PORT_Memcpy(seed->data, firstseed.data, firstseed.len); andre@0: PORT_Memcpy(seed->data+firstseed.len, pseed.data, pseed.len); andre@0: PORT_Memcpy(seed->data+firstseed.len+pseed.len, qseed.data, qseed.len); andre@0: counter = 0 ; /* (qgen_counter << 16) | pgen_counter; */ andre@0: andre@0: /* we've generated both P and Q now, skip to generating G */ andre@0: goto generate_G; andre@0: } andre@0: /* ****************************************************************** andre@0: ** Step 8. (Step 4 in 186-1) andre@0: ** "Use a robust primality testing algorithm to test whether q is prime." andre@0: ** andre@0: ** Appendix 2.1 states that a Rabin test with at least 50 iterations andre@0: ** "will give an acceptable probability of error." andre@0: */ andre@0: /*CHECK_SEC_OK( prm_RabinTest(&Q, &passed) );*/ andre@0: err = mpp_pprime(&Q, prime_testcount_q(L,N)); andre@0: passed = (err == MP_YES) ? SECSuccess : SECFailure; andre@0: /* ****************************************************************** andre@0: ** Step 9. (Step 5 in 186-1) "If q is not prime, goto step 5 (1 in 186-1)." andre@0: */ andre@0: if (passed != SECSuccess) andre@0: goto step_5; andre@0: /* ****************************************************************** andre@0: ** Step 10. andre@0: ** offset = 1; andre@0: **( Step 6b 186-1)"Let counter = 0 and offset = 2." andre@0: */ andre@0: offset = (type == FIPS186_1_TYPE) ? 2 : 1; andre@0: /* andre@0: ** Step 11. (Step 6a,13a,14 in 186-1) andre@0: ** For counter - 0 to (4L-1) do andre@0: ** andre@0: */ andre@0: maxCount = L >= 1024 ? (4*L - 1) : 4095; andre@0: for (counter = 0; counter <= maxCount; counter++) { andre@0: /* ****************************************************************** andre@0: ** Step 11.1 (Step 7 in 186-1) andre@0: ** "for j = 0 ... n let andre@0: ** V_j = HASH[(SEED + offset + j) mod 2**seedlen]." andre@0: ** andre@0: ** Step 11.2 (Step 8 in 186-1) andre@0: ** "W = V_0 + V_1*2**outlen+...+ V_n-1 * 2**((n-1)*outlen) + andre@0: ** ((Vn* mod 2**b)*2**(n*outlen))" andre@0: ** Step 11.3 (Step 8 in 186-1) andre@0: ** "X = W + 2**(L-1) andre@0: ** Note that 0 <= W < 2**(L-1) and hence 2**(L-1) <= X < 2**L." andre@0: ** andre@0: ** Step 11.4 (Step 9 in 186-1). andre@0: ** "c = X mod 2q" andre@0: ** andre@0: ** Step 11.5 (Step 9 in 186-1). andre@0: ** " p = X - (c - 1). andre@0: ** Note that p is congruent to 1 mod 2q." andre@0: */ andre@0: CHECK_SEC_OK( makePfromQandSeed(hashtype, L, N, offset, seedlen, andre@0: seed, &Q, &P) ); andre@0: /************************************************************* andre@0: ** Step 11.6. (Step 10 in 186-1) andre@0: ** "if p < 2**(L-1), then goto step 11.9. (step 13 in 186-1)" andre@0: */ andre@0: CHECK_MPI_OK( mpl_set_bit(&l, (mp_size)(L-1), 1) ); /* l = 2**(L-1) */ andre@0: if (mp_cmp(&P, &l) < 0) andre@0: goto step_11_9; andre@0: /************************************************************ andre@0: ** Step 11.7 (step 11 in 186-1) andre@0: ** "Perform a robust primality test on p." andre@0: */ andre@0: /*CHECK_SEC_OK( prm_RabinTest(&P, &passed) );*/ andre@0: err = mpp_pprime(&P, prime_testcount_p(L, N)); andre@0: passed = (err == MP_YES) ? SECSuccess : SECFailure; andre@0: /* ****************************************************************** andre@0: ** Step 11.8. "If p is determined to be primed return VALID andre@0: ** values of p, q, seed and counter." andre@0: */ andre@0: if (passed == SECSuccess) andre@0: break; andre@0: step_11_9: andre@0: /* ****************************************************************** andre@0: ** Step 11.9. "offset = offset + n + 1." andre@0: */ andre@0: offset += n + 1; andre@0: } andre@0: /* ****************************************************************** andre@0: ** Step 12. "goto step 5." andre@0: ** andre@0: ** NOTE: if counter <= maxCount, then we exited the loop at Step 11.8 andre@0: ** and now need to return p,q, seed, and counter. andre@0: */ andre@0: if (counter > maxCount) andre@0: goto step_5; andre@0: andre@0: generate_G: andre@0: /* ****************************************************************** andre@0: ** returning p, q, seed and counter andre@0: */ andre@0: if (type == FIPS186_1_TYPE) { andre@0: /* Generate g, This is called the "Unverifiable Generation of g andre@0: * in FIPA186-3 Appedix A.2.1. For compatibility we maintain andre@0: * this version of the code */ andre@0: SECITEM_AllocItem(NULL, &hit, L/8); /* h is no longer than p */ andre@0: if (!hit.data) goto cleanup; andre@0: do { andre@0: /* loop generate h until 1 1 */ andre@0: CHECK_SEC_OK( generate_h_candidate(&hit, &H) ); andre@0: CHECK_SEC_OK( makeGfromH(&P, &Q, &H, &G, &passed) ); andre@0: } while (passed != PR_TRUE); andre@0: MPINT_TO_SECITEM(&H, &verify->h, verify->arena); andre@0: } else { andre@0: unsigned char index = 1; /* default to 1 */ andre@0: verify->h.data = (unsigned char *)PORT_ArenaZAlloc(verify->arena, 1); andre@0: if (verify->h.data == NULL) { goto cleanup; } andre@0: verify->h.len = 1; andre@0: verify->h.data[0] = index; andre@0: /* Generate g, using the FIPS 186-3 Appendix A.23 */ andre@0: CHECK_SEC_OK(makeGfromIndex(hashtype, &P, &Q, seed, index, &G) ); andre@0: } andre@0: /* All generation is done. Now, save the PQG params. */ andre@0: MPINT_TO_SECITEM(&P, ¶ms->prime, params->arena); andre@0: MPINT_TO_SECITEM(&Q, ¶ms->subPrime, params->arena); andre@0: MPINT_TO_SECITEM(&G, ¶ms->base, params->arena); andre@0: verify->counter = counter; andre@0: *pParams = params; andre@0: *pVfy = verify; andre@0: cleanup: andre@0: if (pseed.data) { andre@0: PORT_Free(pseed.data); andre@0: } andre@0: if (qseed.data) { andre@0: PORT_Free(qseed.data); andre@0: } andre@0: mp_clear(&P); andre@0: mp_clear(&Q); andre@0: mp_clear(&G); andre@0: mp_clear(&H); andre@0: mp_clear(&l); andre@0: mp_clear(&p0); andre@0: if (err) { andre@0: MP_TO_SEC_ERROR(err); andre@0: rv = SECFailure; andre@0: } andre@0: if (rv) { andre@0: PORT_FreeArena(params->arena, PR_TRUE); andre@0: PORT_FreeArena(verify->arena, PR_TRUE); andre@0: } andre@0: if (hit.data) { andre@0: SECITEM_FreeItem(&hit, PR_FALSE); andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: SECStatus andre@0: PQG_ParamGen(unsigned int j, PQGParams **pParams, PQGVerify **pVfy) andre@0: { andre@0: unsigned int L; /* Length of P in bits. Per FIPS 186. */ andre@0: unsigned int seedBytes; andre@0: andre@0: if (j > 8 || !pParams || !pVfy) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: L = 512 + (j * 64); /* bits in P */ andre@0: seedBytes = L/8; andre@0: return pqg_ParamGen(L, DSA1_Q_BITS, FIPS186_1_TYPE, seedBytes, andre@0: pParams, pVfy); andre@0: } andre@0: andre@0: SECStatus andre@0: PQG_ParamGenSeedLen(unsigned int j, unsigned int seedBytes, andre@0: PQGParams **pParams, PQGVerify **pVfy) andre@0: { andre@0: unsigned int L; /* Length of P in bits. Per FIPS 186. */ andre@0: andre@0: if (j > 8 || !pParams || !pVfy) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: L = 512 + (j * 64); /* bits in P */ andre@0: return pqg_ParamGen(L, DSA1_Q_BITS, FIPS186_1_TYPE, seedBytes, andre@0: pParams, pVfy); andre@0: } andre@0: andre@0: SECStatus andre@0: PQG_ParamGenV2(unsigned int L, unsigned int N, unsigned int seedBytes, andre@0: PQGParams **pParams, PQGVerify **pVfy) andre@0: { andre@0: if (N == 0) { andre@0: N = pqg_get_default_N(L); andre@0: } andre@0: if (seedBytes == 0) { andre@0: /* seedBytes == L/8 for probable primes, N/8 for Shawe-Taylor Primes */ andre@0: seedBytes = N/8; andre@0: } andre@0: if (pqg_validate_dsa2(L,N) != SECSuccess) { andre@0: /* error code already set */ andre@0: return SECFailure; andre@0: } andre@0: return pqg_ParamGen(L, N, FIPS186_3_ST_TYPE, seedBytes, pParams, pVfy); andre@0: } andre@0: andre@0: andre@0: /* andre@0: * verify can use vfy structures returned from either FIPS186-1 or andre@0: * FIPS186-2, and can handle differences in selected Hash functions to andre@0: * generate the parameters. andre@0: */ andre@0: SECStatus andre@0: PQG_VerifyParams(const PQGParams *params, andre@0: const PQGVerify *vfy, SECStatus *result) andre@0: { andre@0: SECStatus rv = SECSuccess; andre@0: unsigned int g, n, L, N, offset, outlen; andre@0: mp_int p0, P, Q, G, P_, Q_, G_, r, h; andre@0: mp_err err = MP_OKAY; andre@0: int j; andre@0: unsigned int counter_max = 0; /* handle legacy L < 1024 */ andre@0: int qseed_len; andre@0: SECItem pseed_ = {0, 0, 0}; andre@0: HASH_HashType hashtype; andre@0: pqgGenType type; andre@0: andre@0: #define CHECKPARAM(cond) \ andre@0: if (!(cond)) { \ andre@0: *result = SECFailure; \ andre@0: goto cleanup; \ andre@0: } andre@0: if (!params || !vfy || !result) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: /* always need at least p, q, and seed for any meaningful check */ andre@0: if ((params->prime.len == 0) || (params->subPrime.len == 0) || andre@0: (vfy->seed.len == 0)) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: /* we want to either check PQ or G or both. If we don't have G, make andre@0: * sure we have count so we can check P. */ andre@0: if ((params->base.len == 0) && (vfy->counter == -1)) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: andre@0: MP_DIGITS(&p0) = 0; andre@0: MP_DIGITS(&P) = 0; andre@0: MP_DIGITS(&Q) = 0; andre@0: MP_DIGITS(&G) = 0; andre@0: MP_DIGITS(&P_) = 0; andre@0: MP_DIGITS(&Q_) = 0; andre@0: MP_DIGITS(&G_) = 0; andre@0: MP_DIGITS(&r) = 0; andre@0: MP_DIGITS(&h) = 0; andre@0: CHECK_MPI_OK( mp_init(&p0) ); andre@0: CHECK_MPI_OK( mp_init(&P) ); andre@0: CHECK_MPI_OK( mp_init(&Q) ); andre@0: CHECK_MPI_OK( mp_init(&G) ); andre@0: CHECK_MPI_OK( mp_init(&P_) ); andre@0: CHECK_MPI_OK( mp_init(&Q_) ); andre@0: CHECK_MPI_OK( mp_init(&G_) ); andre@0: CHECK_MPI_OK( mp_init(&r) ); andre@0: CHECK_MPI_OK( mp_init(&h) ); andre@0: *result = SECSuccess; andre@0: SECITEM_TO_MPINT(params->prime, &P); andre@0: SECITEM_TO_MPINT(params->subPrime, &Q); andre@0: /* if G isn't specified, just check P and Q */ andre@0: if (params->base.len != 0) { andre@0: SECITEM_TO_MPINT(params->base, &G); andre@0: } andre@0: /* 1. Check (L,N) pair */ andre@0: N = mpl_significant_bits(&Q); andre@0: L = mpl_significant_bits(&P); andre@0: if (L < 1024) { andre@0: /* handle DSA1 pqg parameters with less thatn 1024 bits*/ andre@0: CHECKPARAM( N == DSA1_Q_BITS ); andre@0: j = PQG_PBITS_TO_INDEX(L); andre@0: CHECKPARAM( j >= 0 && j <= 8 ); andre@0: counter_max = 4096; andre@0: } else { andre@0: /* handle DSA2 parameters (includes DSA1, 1024 bits) */ andre@0: CHECKPARAM(pqg_validate_dsa2(L, N) == SECSuccess); andre@0: counter_max = 4*L; andre@0: } andre@0: /* 3. G < P */ andre@0: if (params->base.len != 0) { andre@0: CHECKPARAM( mp_cmp(&G, &P) < 0 ); andre@0: } andre@0: /* 4. P % Q == 1 */ andre@0: CHECK_MPI_OK( mp_mod(&P, &Q, &r) ); andre@0: CHECKPARAM( mp_cmp_d(&r, 1) == 0 ); andre@0: /* 5. Q is prime */ andre@0: CHECKPARAM( mpp_pprime(&Q, prime_testcount_q(L,N)) == MP_YES ); andre@0: /* 6. P is prime */ andre@0: CHECKPARAM( mpp_pprime(&P, prime_testcount_p(L,N)) == MP_YES ); andre@0: /* Steps 7-12 are done only if the optional PQGVerify is supplied. */ andre@0: /* continue processing P */ andre@0: /* 7. counter < 4*L */ andre@0: CHECKPARAM( (vfy->counter == -1) || (vfy->counter < counter_max) ); andre@0: /* 8. g >= N and g < 2*L (g is length of seed in bits) */ andre@0: g = vfy->seed.len * 8; andre@0: CHECKPARAM( g >= N && g < counter_max/2 ); andre@0: /* 9. Q generated from SEED matches Q in PQGParams. */ andre@0: /* This function checks all possible hash and generation types to andre@0: * find a Q_ which matches Q. */ andre@0: CHECKPARAM( findQfromSeed(L, N, g, &vfy->seed, &Q, &Q_, &qseed_len, andre@0: &hashtype, &type) == SECSuccess ); andre@0: CHECKPARAM( mp_cmp(&Q, &Q_) == 0 ); andre@0: if (type == FIPS186_3_ST_TYPE) { andre@0: SECItem qseed = { 0, 0, 0 }; andre@0: SECItem pseed = { 0, 0, 0 }; andre@0: int first_seed_len; andre@0: int pgen_counter = 0; andre@0: andre@0: /* extract pseed and qseed from domain_parameter_seed, which is andre@0: * first_seed || pseed || qseed. qseed is first_seed + small_integer andre@0: * pseed is qseed + small_integer. This means most of the time andre@0: * first_seed.len == qseed.len == pseed.len. Rarely qseed.len and/or andre@0: * pseed.len will be one greater than first_seed.len, so we can andre@0: * depend on the fact that andre@0: * first_seed.len = floor(domain_parameter_seed.len/3). andre@0: * findQfromSeed returned qseed.len, so we can calculate pseed.len as andre@0: * pseed.len = domain_parameter_seed.len - first_seed.len - qseed.len andre@0: * this is probably over kill, since 99.999% of the time they will all andre@0: * be equal. andre@0: * andre@0: * With the lengths, we can now find the offsets; andre@0: * first_seed.data = domain_parameter_seed.data + 0 andre@0: * pseed.data = domain_parameter_seed.data + first_seed.len andre@0: * qseed.data = domain_parameter_seed.data andre@0: * + domain_paramter_seed.len - qseed.len andre@0: * andre@0: */ andre@0: first_seed_len = vfy->seed.len/3; andre@0: CHECKPARAM(qseed_len < vfy->seed.len); andre@0: CHECKPARAM(first_seed_len*8 > N-1); andre@0: CHECKPARAM(first_seed_len+qseed_len < vfy->seed.len); andre@0: qseed.len = qseed_len; andre@0: qseed.data = vfy->seed.data + vfy->seed.len - qseed.len; andre@0: pseed.len = vfy->seed.len - (first_seed_len+qseed_len); andre@0: pseed.data = vfy->seed.data + first_seed_len; andre@0: andre@0: /* andre@0: * now complete FIPS 186-3 A.1.2.1.2. Step 1 was completed andre@0: * above in our initial checks, Step 2 was completed by andre@0: * findQfromSeed */ andre@0: andre@0: /* Step 3 (status, c0, prime_seed, prime_gen_counter) = andre@0: ** (ST_Random_Prime((ceil(length/2)+1, input_seed) andre@0: */ andre@0: CHECK_SEC_OK( makePrimefromSeedShaweTaylor(hashtype, (L+1)/2+1, andre@0: &qseed, &p0, &pseed_, &pgen_counter) ); andre@0: /* Steps 4-22 FIPS 186-3 appendix A.1.2.1.2 */ andre@0: CHECK_SEC_OK( makePrimefromPrimesShaweTaylor(hashtype, L, andre@0: &p0, &Q_, &P_, &pseed_, &pgen_counter) ); andre@0: CHECKPARAM( mp_cmp(&P, &P_) == 0 ); andre@0: /* make sure pseed wasn't tampered with (since it is part of andre@0: * calculating G) */ andre@0: CHECKPARAM( SECITEM_CompareItem(&pseed, &pseed_) == SECEqual ); andre@0: } else if (vfy->counter == -1) { andre@0: /* If counter is set to -1, we are really only verifying G, skip andre@0: * the remainder of the checks for P */ andre@0: CHECKPARAM(type != FIPS186_1_TYPE); /* we only do this for DSA2 */ andre@0: } else { andre@0: /* 10. P generated from (L, counter, g, SEED, Q) matches P andre@0: * in PQGParams. */ andre@0: outlen = HASH_ResultLen(hashtype)*PR_BITS_PER_BYTE; andre@0: n = (L - 1) / outlen; andre@0: offset = vfy->counter * (n + 1) + ((type == FIPS186_1_TYPE) ? 2 : 1); andre@0: CHECK_SEC_OK( makePfromQandSeed(hashtype, L, N, offset, g, &vfy->seed, andre@0: &Q, &P_) ); andre@0: CHECKPARAM( mp_cmp(&P, &P_) == 0 ); andre@0: } andre@0: andre@0: /* now check G, skip if don't have a g */ andre@0: if (params->base.len == 0) goto cleanup; andre@0: andre@0: /* first Always check that G is OK FIPS186-3 A.2.2 & A.2.4*/ andre@0: /* 1. 2 < G < P-1 */ andre@0: /* P is prime, p-1 == zero 1st bit */ andre@0: CHECK_MPI_OK( mpl_set_bit(&P, 0, 0) ); andre@0: CHECKPARAM( mp_cmp_d(&G, 2) > 0 && mp_cmp(&G, &P) < 0 ); andre@0: CHECK_MPI_OK( mpl_set_bit(&P, 0, 1) ); /* set it back */ andre@0: /* 2. verify g**q mod p == 1 */ andre@0: CHECK_MPI_OK( mp_exptmod(&G, &Q, &P, &h) ); /* h = G ** Q mod P */ andre@0: CHECKPARAM(mp_cmp_d(&h, 1) == 0); andre@0: andre@0: /* no h, the above is the best we can do */ andre@0: if (vfy->h.len == 0) { andre@0: if (type != FIPS186_1_TYPE) { andre@0: *result = SECWouldBlock; andre@0: } andre@0: goto cleanup; andre@0: } andre@0: andre@0: /* andre@0: * If h is one byte and FIPS186-3 was used to generate Q (we've verified andre@0: * Q was generated from seed already, then we assume that FIPS 186-3 andre@0: * appendix A.2.3 was used to generate G. Otherwise we assume A.2.1 was andre@0: * used to generate G. andre@0: */ andre@0: if ((vfy->h.len == 1) && (type != FIPS186_1_TYPE)) { andre@0: /* A.2.3 */ andre@0: CHECK_SEC_OK(makeGfromIndex(hashtype, &P, &Q, &vfy->seed, andre@0: vfy->h.data[0], &G_) ); andre@0: CHECKPARAM( mp_cmp(&G, &G_) == 0 ); andre@0: } else { andre@0: int passed; andre@0: /* A.2.1 */ andre@0: SECITEM_TO_MPINT(vfy->h, &h); andre@0: /* 11. 1 < h < P-1 */ andre@0: /* P is prime, p-1 == zero 1st bit */ andre@0: CHECK_MPI_OK( mpl_set_bit(&P, 0, 0) ); andre@0: CHECKPARAM( mp_cmp_d(&G, 2) > 0 && mp_cmp(&G, &P) ); andre@0: CHECK_MPI_OK( mpl_set_bit(&P, 0, 1) ); /* set it back */ andre@0: /* 12. G generated from h matches G in PQGParams. */ andre@0: CHECK_SEC_OK( makeGfromH(&P, &Q, &h, &G_, &passed) ); andre@0: CHECKPARAM( passed && mp_cmp(&G, &G_) == 0 ); andre@0: } andre@0: cleanup: andre@0: mp_clear(&p0); andre@0: mp_clear(&P); andre@0: mp_clear(&Q); andre@0: mp_clear(&G); andre@0: mp_clear(&P_); andre@0: mp_clear(&Q_); andre@0: mp_clear(&G_); andre@0: mp_clear(&r); andre@0: mp_clear(&h); andre@0: if (pseed_.data) { andre@0: SECITEM_FreeItem(&pseed_,PR_FALSE); andre@0: } andre@0: if (err) { andre@0: MP_TO_SEC_ERROR(err); andre@0: rv = SECFailure; andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: /************************************************************************** andre@0: * Free the PQGParams struct and the things it points to. * andre@0: **************************************************************************/ andre@0: void andre@0: PQG_DestroyParams(PQGParams *params) andre@0: { andre@0: if (params == NULL) andre@0: return; andre@0: if (params->arena != NULL) { andre@0: PORT_FreeArena(params->arena, PR_FALSE); /* don't zero it */ andre@0: } else { andre@0: SECITEM_FreeItem(¶ms->prime, PR_FALSE); /* don't free prime */ andre@0: SECITEM_FreeItem(¶ms->subPrime, PR_FALSE); /* don't free subPrime */ andre@0: SECITEM_FreeItem(¶ms->base, PR_FALSE); /* don't free base */ andre@0: PORT_Free(params); andre@0: } andre@0: } andre@0: andre@0: /************************************************************************** andre@0: * Free the PQGVerify struct and the things it points to. * andre@0: **************************************************************************/ andre@0: andre@0: void andre@0: PQG_DestroyVerify(PQGVerify *vfy) andre@0: { andre@0: if (vfy == NULL) andre@0: return; andre@0: if (vfy->arena != NULL) { andre@0: PORT_FreeArena(vfy->arena, PR_FALSE); /* don't zero it */ andre@0: } else { andre@0: SECITEM_FreeItem(&vfy->seed, PR_FALSE); /* don't free seed */ andre@0: SECITEM_FreeItem(&vfy->h, PR_FALSE); /* don't free h */ andre@0: PORT_Free(vfy); andre@0: } andre@0: }