Index: mozilla/security/nss/lib/freebl/dsa.c |
=================================================================== |
--- mozilla/security/nss/lib/freebl/dsa.c (revision 158129) |
+++ mozilla/security/nss/lib/freebl/dsa.c (working copy) |
@@ -20,6 +20,7 @@ |
#include "blapi.h" |
#include "mpi.h" |
#include "secmpi.h" |
+#include "pqg.h" |
/* XXX to be replaced by define in blapit.h */ |
#define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048 |
@@ -79,7 +80,7 @@ |
FIPS186Change_ReduceModQForDSA(const unsigned char *w, |
const unsigned char *q, |
unsigned char *xj) { |
- return fips186Change_ReduceModQForDSA(w, q, DSA_SUBPRIME_LEN, xj); |
+ return fips186Change_ReduceModQForDSA(w, q, DSA1_SUBPRIME_LEN, xj); |
} |
/* |
@@ -127,7 +128,7 @@ |
} |
if (maxDestLen < qLen) { |
/* This condition can occur when DSA_SignDigest is passed a group |
- with a subprime that is larger than DSA_SUBPRIME_LEN. */ |
+ with a subprime that is larger than DSA_MAX_SUBPRIME_LEN. */ |
PORT_SetError(SEC_ERROR_INVALID_ARGS); |
return SECFailure; |
} |
@@ -279,11 +280,15 @@ |
SECItem seed; |
SECStatus rv; |
+ rv = PQG_Check(params); |
+ if (rv != SECSuccess) { |
+ return rv; |
+ } |
seed.data = NULL; |
rv = DSA_NewRandom(NULL, ¶ms->subPrime, &seed); |
if (rv == SECSuccess) { |
- if (seed.len != DSA_SUBPRIME_LEN) { |
+ if (seed.len != PQG_GetLength(¶ms->subPrime)) { |
PORT_SetError(SEC_ERROR_INVALID_ARGS); |
rv = SECFailure; |
} else { |
@@ -294,16 +299,15 @@ |
return rv; |
} |
-/* For FIPS compliance testing. Seed must be exactly 20 bytes long */ |
+/* For FIPS compliance testing. Seed must be exactly the size of subPrime */ |
SECStatus |
DSA_NewKeyFromSeed(const PQGParams *params, |
const unsigned char *seed, |
DSAPrivateKey **privKey) |
{ |
- /* TODO: check Q size */ |
SECItem seedItem; |
seedItem.data = (unsigned char*) seed; |
- seedItem.len = DSA_SUBPRIME_LEN; |
+ seedItem.len = PQG_GetLength(¶ms->subPrime); |
return dsa_NewKeyExtended(params, &seedItem, privKey); |
} |
@@ -316,16 +320,39 @@ |
mp_int r, s; /* tuple (r, s) is signature) */ |
mp_err err = MP_OKAY; |
SECStatus rv = SECSuccess; |
+ unsigned int dsa_subprime_len, dsa_signature_len, offset; |
+ SECItem localDigest; |
+ unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN]; |
+ |
- /* FIPS-compliance dictates that digest is a SHA1 hash. */ |
+ /* FIPS-compliance dictates that digest is a SHA hash. */ |
/* Check args. */ |
- if (!key || !signature || !digest || |
- (signature->len < DSA_SIGNATURE_LEN) || |
- (digest->len != SHA1_LENGTH)) { |
+ if (!key || !signature || !digest) { |
PORT_SetError(SEC_ERROR_INVALID_ARGS); |
return SECFailure; |
} |
+ dsa_subprime_len = PQG_GetLength(&key->params.subPrime); |
+ dsa_signature_len = dsa_subprime_len*2; |
+ if ((signature->len < dsa_signature_len) || |
+ (digest->len > HASH_LENGTH_MAX) || |
+ (digest->len < SHA1_LENGTH)) { |
+ PORT_SetError(SEC_ERROR_INVALID_ARGS); |
+ return SECFailure; |
+ } |
+ |
+ /* DSA accepts digests not equal to dsa_subprime_len, if the |
+ * digests are greater, then they are truncated to the size of |
+ * dsa_subprime_len, using the left most bits. If they are less |
+ * then they are padded on the left.*/ |
+ PORT_Memset(localDigestData, 0, dsa_subprime_len); |
+ offset = (digest->len < dsa_subprime_len) ? |
+ (dsa_subprime_len - digest->len) : 0; |
+ PORT_Memcpy(localDigestData+offset, digest->data, |
+ dsa_subprime_len - offset); |
+ localDigest.data = localDigestData; |
+ localDigest.len = dsa_subprime_len; |
+ |
/* Initialize MPI integers. */ |
MP_DIGITS(&p) = 0; |
MP_DIGITS(&q) = 0; |
@@ -348,7 +375,7 @@ |
SECITEM_TO_MPINT(key->params.subPrime, &q); |
SECITEM_TO_MPINT(key->params.base, &g); |
SECITEM_TO_MPINT(key->privateValue, &x); |
- OCTETS_TO_MPINT(kb, &k, DSA_SUBPRIME_LEN); |
+ OCTETS_TO_MPINT(kb, &k, dsa_subprime_len); |
/* |
** FIPS 186-1, Section 5, Step 1 |
** |
@@ -359,9 +386,9 @@ |
/* |
** FIPS 186-1, Section 5, Step 2 |
** |
- ** s = (k**-1 * (SHA1(M) + x*r)) mod q |
+ ** s = (k**-1 * (HASH(M) + x*r)) mod q |
*/ |
- SECITEM_TO_MPINT(*digest, &s); /* s = SHA1(M) */ |
+ SECITEM_TO_MPINT(localDigest, &s); /* s = HASH(M) */ |
CHECK_MPI_OK( mp_invmod(&k, &q, &k) ); /* k = k**-1 mod q */ |
CHECK_MPI_OK( mp_mulmod(&x, &r, &q, &x) ); /* x = x * r mod q */ |
CHECK_MPI_OK( mp_addmod(&s, &x, &q, &s) ); /* s = s + x mod q */ |
@@ -380,14 +407,15 @@ |
** |
** Signature is tuple (r, s) |
*/ |
- err = mp_to_fixlen_octets(&r, signature->data, DSA_SUBPRIME_LEN); |
+ err = mp_to_fixlen_octets(&r, signature->data, dsa_subprime_len); |
if (err < 0) goto cleanup; |
- err = mp_to_fixlen_octets(&s, signature->data + DSA_SUBPRIME_LEN, |
- DSA_SUBPRIME_LEN); |
+ err = mp_to_fixlen_octets(&s, signature->data + dsa_subprime_len, |
+ dsa_subprime_len); |
if (err < 0) goto cleanup; |
err = MP_OKAY; |
- signature->len = DSA_SIGNATURE_LEN; |
+ signature->len = dsa_signature_len; |
cleanup: |
+ PORT_Memset(localDigestData, 0, DSA_MAX_SUBPRIME_LEN); |
mp_clear(&p); |
mp_clear(&q); |
mp_clear(&g); |
@@ -413,9 +441,10 @@ |
{ |
SECStatus rv; |
int retries = 10; |
- unsigned char kSeed[DSA_SUBPRIME_LEN]; |
+ unsigned char kSeed[DSA_MAX_SUBPRIME_LEN]; |
unsigned int kSeedLen = 0; |
unsigned int i; |
+ unsigned int dsa_subprime_len = PQG_GetLength(&key->params.subPrime); |
PRBool good; |
PORT_SetError(0); |
@@ -424,7 +453,7 @@ |
kSeed, &kSeedLen, sizeof kSeed); |
if (rv != SECSuccess) |
break; |
- if (kSeedLen != DSA_SUBPRIME_LEN) { |
+ if (kSeedLen != dsa_subprime_len) { |
PORT_SetError(SEC_ERROR_INVALID_ARGS); |
rv = SECFailure; |
break; |
@@ -468,21 +497,44 @@ |
DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature, |
const SECItem *digest) |
{ |
- /* FIPS-compliance dictates that digest is a SHA1 hash. */ |
+ /* FIPS-compliance dictates that digest is a SHA hash. */ |
mp_int p, q, g; /* PQG parameters */ |
mp_int r_, s_; /* tuple (r', s') is received signature) */ |
mp_int u1, u2, v, w; /* intermediate values used in verification */ |
mp_int y; /* public key */ |
mp_err err; |
+ int dsa_subprime_len, dsa_signature_len, offset; |
+ SECItem localDigest; |
+ unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN]; |
SECStatus verified = SECFailure; |
/* Check args. */ |
- if (!key || !signature || !digest || |
- (signature->len != DSA_SIGNATURE_LEN) || |
- (digest->len != SHA1_LENGTH)) { |
+ if (!key || !signature || !digest ) { |
PORT_SetError(SEC_ERROR_INVALID_ARGS); |
return SECFailure; |
} |
+ |
+ dsa_subprime_len = PQG_GetLength(&key->params.subPrime); |
+ dsa_signature_len = dsa_subprime_len*2; |
+ if ((signature->len != dsa_signature_len) || |
+ (digest->len > HASH_LENGTH_MAX) || |
+ (digest->len < SHA1_LENGTH)) { |
+ PORT_SetError(SEC_ERROR_INVALID_ARGS); |
+ return SECFailure; |
+ } |
+ |
+ /* DSA accepts digests not equal to dsa_subprime_len, if the |
+ * digests are greater, than they are truncated to the size of |
+ * dsa_subprime_len, using the left most bits. If they are less |
+ * then they are padded on the left.*/ |
+ PORT_Memset(localDigestData, 0, dsa_subprime_len); |
+ offset = (digest->len < dsa_subprime_len) ? |
+ (dsa_subprime_len - digest->len) : 0; |
+ PORT_Memcpy(localDigestData+offset, digest->data, |
+ dsa_subprime_len - offset); |
+ localDigest.data = localDigestData; |
+ localDigest.len = dsa_subprime_len; |
+ |
/* Initialize MPI integers. */ |
MP_DIGITS(&p) = 0; |
MP_DIGITS(&q) = 0; |
@@ -514,8 +566,8 @@ |
/* |
** Convert received signature (r', s') into MPI integers. |
*/ |
- OCTETS_TO_MPINT(signature->data, &r_, DSA_SUBPRIME_LEN); |
- OCTETS_TO_MPINT(signature->data + DSA_SUBPRIME_LEN, &s_, DSA_SUBPRIME_LEN); |
+ OCTETS_TO_MPINT(signature->data, &r_, dsa_subprime_len); |
+ OCTETS_TO_MPINT(signature->data + dsa_subprime_len, &s_, dsa_subprime_len); |
/* |
** Verify that 0 < r' < q and 0 < s' < q |
*/ |
@@ -534,9 +586,9 @@ |
/* |
** FIPS 186-1, Section 6, Step 2 |
** |
- ** u1 = ((SHA1(M')) * w) mod q |
+ ** u1 = ((Hash(M')) * w) mod q |
*/ |
- SECITEM_TO_MPINT(*digest, &u1); /* u1 = SHA1(M') */ |
+ SECITEM_TO_MPINT(localDigest, &u1); /* u1 = HASH(M') */ |
CHECK_MPI_OK( mp_mulmod(&u1, &w, &q, &u1) ); /* u1 = u1 * w mod q */ |
/* |
** FIPS 186-1, Section 6, Step 3 |