Bug 1631576 - Force a fixed length for DSA exponentiation r=pereida,bbrumley NSS_3_52_BRANCH
authorRobert Relyea <rrelyea@redhat.com>
Thu, 23 Apr 2020 20:48:28 +0000
branchNSS_3_52_BRANCH
changeset 15612 a5a9937948c8e3dba3a8065781f0ade74be1259e
parent 15584 92f61e8d82032bb01c507fd7acf26fc044bdf818
child 15613 83d296f12b3ecec5b2e5bd2f2d1349b8ed34cb81
push id3745
push userjjones@mozilla.com
push dateTue, 19 May 2020 21:34:45 +0000
reviewerspereida, bbrumley
bugs1631576
Bug 1631576 - Force a fixed length for DSA exponentiation r=pereida,bbrumley Differential Revision: https://phabricator.services.mozilla.com/D72011
lib/freebl/dsa.c
--- a/lib/freebl/dsa.c
+++ b/lib/freebl/dsa.c
@@ -308,23 +308,24 @@ DSA_NewKeyFromSeed(const PQGParams *para
     SECItem seedItem;
     seedItem.data = (unsigned char *)seed;
     seedItem.len = PQG_GetLength(&params->subPrime);
     return dsa_NewKeyExtended(params, &seedItem, privKey);
 }
 
 static SECStatus
 dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
-               const unsigned char *kb)
+               const unsigned char *kbytes)
 {
     mp_int p, q, g; /* PQG parameters */
     mp_int x, k;    /* private key & pseudo-random integer */
     mp_int r, s;    /* tuple (r, s) is signature) */
     mp_int t;       /* holding tmp values */
     mp_int ar;      /* holding blinding values */
+    mp_digit fuzz;  /* blinding multiplier for q */
     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];
     SECItem t2 = { siBuffer, NULL, 0 };
 
     /* FIPS-compliance dictates that digest is a SHA hash. */
@@ -368,31 +369,46 @@ dsa_SignDigest(DSAPrivateKey *key, SECIt
     CHECK_MPI_OK(mp_init(&q));
     CHECK_MPI_OK(mp_init(&g));
     CHECK_MPI_OK(mp_init(&x));
     CHECK_MPI_OK(mp_init(&k));
     CHECK_MPI_OK(mp_init(&r));
     CHECK_MPI_OK(mp_init(&s));
     CHECK_MPI_OK(mp_init(&t));
     CHECK_MPI_OK(mp_init(&ar));
+
     /*
     ** Convert stored PQG and private key into MPI integers.
     */
     SECITEM_TO_MPINT(key->params.prime, &p);
     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(kbytes, &k, dsa_subprime_len);
+
+    /* k blinding  create a single value that has the high bit set in
+     * the mp_digit*/
+    if (RNG_GenerateGlobalRandomBytes(&fuzz, sizeof(mp_digit)) != SECSuccess) {
+        PORT_SetError(SEC_ERROR_NEED_RANDOM);
+        rv = SECFailure;
+        goto cleanup;
+    }
+    fuzz |= 1ULL << ((sizeof(mp_digit) * PR_BITS_PER_BYTE - 1));
     /*
     ** FIPS 186-1, Section 5, Step 1
     **
     ** r = (g**k mod p) mod q
     */
-    CHECK_MPI_OK(mp_exptmod(&g, &k, &p, &r)); /* r = g**k mod p */
-    CHECK_MPI_OK(mp_mod(&r, &q, &r));         /* r = r mod q    */
+    CHECK_MPI_OK(mp_mul_d(&q, fuzz, &t)); /* t = q*fuzz */
+    CHECK_MPI_OK(mp_add(&k, &t, &t));     /* t = k+q*fuzz */
+    /* length of t is now fixed, bits in k have been blinded */
+    CHECK_MPI_OK(mp_exptmod(&g, &t, &p, &r)); /* r = g**t mod p */
+    /* r is now g**(k+q*fuzz) == g**k mod p */
+    CHECK_MPI_OK(mp_mod(&r, &q, &r)); /* r = r mod q    */
+
     /*
     ** FIPS 186-1, Section 5, Step 2
     **
     ** s = (k**-1 * (HASH(M) + x*r)) mod q
     */
     if (DSA_NewRandom(NULL, &key->params.subPrime, &t2) != SECSuccess) {
         PORT_SetError(SEC_ERROR_NEED_RANDOM);
         rv = SECFailure;
@@ -406,25 +422,34 @@ dsa_SignDigest(DSAPrivateKey *key, SECIt
         goto cleanup;
     }
     SECITEM_TO_MPINT(t2, &ar); /* ar <-$ Zq */
     SECITEM_FreeItem(&t2, PR_FALSE);
 
     /* Using mp_invmod on k directly would leak bits from k. */
     CHECK_MPI_OK(mp_mul(&k, &ar, &k));       /* k = k * ar */
     CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */
-    CHECK_MPI_OK(mp_invmod(&k, &q, &k));     /* k = k**-1 mod q */
+    /* k is now k*t*ar */
+    CHECK_MPI_OK(mp_invmod(&k, &q, &k)); /* k = k**-1 mod q */
+    /* k is now (k*t*ar)**-1 */
     CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */
-    SECITEM_TO_MPINT(localDigest, &s);       /* s = HASH(M)     */
+    /* k is now (k*ar)**-1 */
+    SECITEM_TO_MPINT(localDigest, &s); /* s = HASH(M)     */
     /* To avoid leaking secret bits here the addition is blinded. */
-    CHECK_MPI_OK(mp_mul(&x, &ar, &x));        /* x = x * ar */
-    CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x));  /* x = x * r mod q */
+    CHECK_MPI_OK(mp_mul(&x, &ar, &x)); /* x = x * ar */
+    /* x is now x*ar */
+    CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x)); /* x = x * r mod q */
+    /* x is now x*r*ar */
     CHECK_MPI_OK(mp_mulmod(&s, &ar, &q, &t)); /* t = s * ar mod q */
-    CHECK_MPI_OK(mp_add(&t, &x, &s));         /* s = t + x */
-    CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s));  /* s = s * k mod q */
+    /* t is now hash(M)*ar */
+    CHECK_MPI_OK(mp_add(&t, &x, &s)); /* s = t + x */
+    /* s is now (HASH(M)+x*r)*ar */
+    CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s)); /* s = s * k mod q */
+    /* s is now (HASH(M)+x*r)*ar*(k*ar)**-1 = (k**-1)*(HASH(M)+x*r) */
+
     /*
     ** verify r != 0 and s != 0
     ** mentioned as optional in FIPS 186-1.
     */
     if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) {
         PORT_SetError(SEC_ERROR_NEED_RANDOM);
         rv = SECFailure;
         goto cleanup;