tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dsa.c (21339B)


      1 /*
      2 *
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifdef FREEBL_NO_DEPEND
      8 #include "stubs.h"
      9 #endif
     10 
     11 #include "prerror.h"
     12 #include "secerr.h"
     13 
     14 #include "prtypes.h"
     15 #include "prinit.h"
     16 #include "blapi.h"
     17 #include "nssilock.h"
     18 #include "secitem.h"
     19 #include "blapit.h"
     20 #include "mpi.h"
     21 #include "secmpi.h"
     22 #include "pqg.h"
     23 
     24 /*
     25 * FIPS 186-2 requires result from random output to be reduced mod q when
     26 * generating random numbers for DSA.
     27 *
     28 * Input: w, 2*qLen bytes
     29 *        q, qLen bytes
     30 * Output: xj, qLen bytes
     31 */
     32 static SECStatus
     33 fips186Change_ReduceModQForDSA(const PRUint8 *w, const PRUint8 *q,
     34                               unsigned int qLen, PRUint8 *xj)
     35 {
     36    mp_int W, Q, Xj;
     37    mp_err err;
     38    SECStatus rv = SECSuccess;
     39 
     40    /* Initialize MPI integers. */
     41    MP_DIGITS(&W) = 0;
     42    MP_DIGITS(&Q) = 0;
     43    MP_DIGITS(&Xj) = 0;
     44    CHECK_MPI_OK(mp_init(&W));
     45    CHECK_MPI_OK(mp_init(&Q));
     46    CHECK_MPI_OK(mp_init(&Xj));
     47    /*
     48     * Convert input arguments into MPI integers.
     49     */
     50    CHECK_MPI_OK(mp_read_unsigned_octets(&W, w, 2 * qLen));
     51    CHECK_MPI_OK(mp_read_unsigned_octets(&Q, q, qLen));
     52 
     53    /*
     54     * Algorithm 1 of FIPS 186-2 Change Notice 1, Step 3.3
     55     *
     56     * xj = (w0 || w1) mod q
     57     */
     58    CHECK_MPI_OK(mp_mod(&W, &Q, &Xj));
     59    CHECK_MPI_OK(mp_to_fixlen_octets(&Xj, xj, qLen));
     60 cleanup:
     61    mp_clear(&W);
     62    mp_clear(&Q);
     63    mp_clear(&Xj);
     64    if (err) {
     65        MP_TO_SEC_ERROR(err);
     66        rv = SECFailure;
     67    }
     68    return rv;
     69 }
     70 
     71 /*
     72 * FIPS 186-2 requires result from random output to be reduced mod q when
     73 * generating random numbers for DSA.
     74 */
     75 SECStatus
     76 FIPS186Change_ReduceModQForDSA(const unsigned char *w,
     77                               const unsigned char *q,
     78                               unsigned char *xj)
     79 {
     80    return fips186Change_ReduceModQForDSA(w, q, DSA1_SUBPRIME_LEN, xj);
     81 }
     82 
     83 /*
     84 * The core of Algorithm 1 of FIPS 186-2 Change Notice 1.
     85 *
     86 * We no longer support FIPS 186-2 RNG. This function was exported
     87 * for power-up self tests and FIPS tests. Keep this stub, which fails,
     88 * to prevent crashes, but also to signal to test code that FIPS 186-2
     89 * RNG is no longer supported.
     90 */
     91 SECStatus
     92 FIPS186Change_GenerateX(PRUint8 *XKEY, const PRUint8 *XSEEDj,
     93                        PRUint8 *x_j)
     94 {
     95    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
     96    return SECFailure;
     97 }
     98 
     99 /*
    100 * Specialized RNG for DSA
    101 *
    102 * As per Algorithm 1 of FIPS 186-2 Change Notice 1, in step 3.3 the value
    103 * Xj should be reduced mod q, a 160-bit prime number.  Since this parameter
    104 * is only meaningful in the context of DSA, the above RNG functions
    105 * were implemented without it.  They are re-implemented below for use
    106 * with DSA.
    107 */
    108 
    109 /*
    110 ** Generate some random bytes, using the global random number generator
    111 ** object.  In DSA mode, so there is a q.
    112 */
    113 static SECStatus
    114 dsa_GenerateGlobalRandomBytes(const SECItem *qItem, PRUint8 *dest,
    115                              unsigned int *destLen, unsigned int maxDestLen)
    116 {
    117    SECStatus rv;
    118    SECItem w;
    119    const PRUint8 *q = qItem->data;
    120    unsigned int qLen = qItem->len;
    121 
    122    if (*q == 0) {
    123        ++q;
    124        --qLen;
    125    }
    126    if (maxDestLen < qLen) {
    127        /* This condition can occur when DSA_SignDigest is passed a group
    128           with a subprime that is larger than DSA_MAX_SUBPRIME_LEN. */
    129        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    130        return SECFailure;
    131    }
    132    w.data = NULL; /* otherwise SECITEM_AllocItem asserts */
    133    if (!SECITEM_AllocItem(NULL, &w, 2 * qLen)) {
    134        return SECFailure;
    135    }
    136    *destLen = qLen;
    137 
    138    rv = RNG_GenerateGlobalRandomBytes(w.data, w.len);
    139    if (rv == SECSuccess) {
    140        rv = fips186Change_ReduceModQForDSA(w.data, q, qLen, dest);
    141    }
    142 
    143    SECITEM_FreeItem(&w, PR_FALSE);
    144    return rv;
    145 }
    146 
    147 static void
    148 translate_mpi_error(mp_err err)
    149 {
    150    MP_TO_SEC_ERROR(err);
    151 }
    152 
    153 static SECStatus
    154 dsa_NewKeyExtended(const PQGParams *params, const SECItem *seed,
    155                   DSAPrivateKey **privKey)
    156 {
    157    mp_int p, g;
    158    mp_int x, y;
    159    mp_err err;
    160    PLArenaPool *arena;
    161    DSAPrivateKey *key;
    162    /* Check args. */
    163    if (!params || !privKey || !seed || !seed->data) {
    164        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    165        return SECFailure;
    166    }
    167    /* Initialize an arena for the DSA key. */
    168    arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
    169    if (!arena) {
    170        PORT_SetError(SEC_ERROR_NO_MEMORY);
    171        return SECFailure;
    172    }
    173    key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
    174    if (!key) {
    175        PORT_SetError(SEC_ERROR_NO_MEMORY);
    176        PORT_FreeArena(arena, PR_TRUE);
    177        return SECFailure;
    178    }
    179    key->params.arena = arena;
    180    /* Initialize MPI integers. */
    181    MP_DIGITS(&p) = 0;
    182    MP_DIGITS(&g) = 0;
    183    MP_DIGITS(&x) = 0;
    184    MP_DIGITS(&y) = 0;
    185    CHECK_MPI_OK(mp_init(&p));
    186    CHECK_MPI_OK(mp_init(&g));
    187    CHECK_MPI_OK(mp_init(&x));
    188    CHECK_MPI_OK(mp_init(&y));
    189    /* Copy over the PQG params */
    190    CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.prime,
    191                                  &params->prime));
    192    CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.subPrime,
    193                                  &params->subPrime));
    194    CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.base, &params->base));
    195    /* Convert stored p, g, and received x into MPI integers. */
    196    SECITEM_TO_MPINT(params->prime, &p);
    197    SECITEM_TO_MPINT(params->base, &g);
    198    OCTETS_TO_MPINT(seed->data, &x, seed->len);
    199    /* Store x in private key */
    200    SECITEM_AllocItem(arena, &key->privateValue, seed->len);
    201    PORT_Memcpy(key->privateValue.data, seed->data, seed->len);
    202    /* Compute public key y = g**x mod p */
    203    CHECK_MPI_OK(mp_exptmod(&g, &x, &p, &y));
    204    /* Store y in public key */
    205    MPINT_TO_SECITEM(&y, &key->publicValue, arena);
    206    *privKey = key;
    207    key = NULL;
    208 cleanup:
    209    mp_clear(&p);
    210    mp_clear(&g);
    211    mp_clear(&x);
    212    mp_clear(&y);
    213    if (key) {
    214        PORT_FreeArena(key->params.arena, PR_TRUE);
    215    }
    216    if (err) {
    217        translate_mpi_error(err);
    218        return SECFailure;
    219    }
    220    return SECSuccess;
    221 }
    222 
    223 SECStatus
    224 DSA_NewRandom(PLArenaPool *arena, const SECItem *q, SECItem *seed)
    225 {
    226    int retries = 10;
    227    unsigned int i;
    228    PRBool good;
    229 
    230    if (q == NULL || q->data == NULL || q->len == 0 ||
    231        (q->data[0] == 0 && q->len == 1)) {
    232        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    233        return SECFailure;
    234    }
    235 
    236    if (!SECITEM_AllocItem(arena, seed, q->len)) {
    237        return SECFailure;
    238    }
    239 
    240    do {
    241        /* Generate seed bytes for x according to FIPS 186-1 appendix 3 */
    242        if (dsa_GenerateGlobalRandomBytes(q, seed->data, &seed->len,
    243                                          seed->len)) {
    244            goto loser;
    245        }
    246        /* Disallow values of 0 and 1 for x. */
    247        good = PR_FALSE;
    248        for (i = 0; i < seed->len - 1; i++) {
    249            if (seed->data[i] != 0) {
    250                good = PR_TRUE;
    251                break;
    252            }
    253        }
    254        if (!good && seed->data[i] > 1) {
    255            good = PR_TRUE;
    256        }
    257    } while (!good && --retries > 0);
    258 
    259    if (!good) {
    260        PORT_SetError(SEC_ERROR_NEED_RANDOM);
    261    loser:
    262        if (arena != NULL) {
    263            SECITEM_ZfreeItem(seed, PR_FALSE);
    264        }
    265        return SECFailure;
    266    }
    267 
    268    return SECSuccess;
    269 }
    270 
    271 /*
    272 ** Generate and return a new DSA public and private key pair,
    273 **  both of which are encoded into a single DSAPrivateKey struct.
    274 **  "params" is a pointer to the PQG parameters for the domain
    275 **  Uses a random seed.
    276 */
    277 SECStatus
    278 DSA_NewKey(const PQGParams *params, DSAPrivateKey **privKey)
    279 {
    280    SECItem seed;
    281    SECStatus rv;
    282 
    283    rv = PQG_Check(params);
    284    if (rv != SECSuccess) {
    285        return rv;
    286    }
    287    seed.data = NULL;
    288 
    289    rv = DSA_NewRandom(NULL, &params->subPrime, &seed);
    290    if (rv == SECSuccess) {
    291        if (seed.len != PQG_GetLength(&params->subPrime)) {
    292            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    293            rv = SECFailure;
    294        } else {
    295            rv = dsa_NewKeyExtended(params, &seed, privKey);
    296        }
    297    }
    298    SECITEM_ZfreeItem(&seed, PR_FALSE);
    299    return rv;
    300 }
    301 
    302 /* For FIPS compliance testing. Seed must be exactly the size of subPrime  */
    303 SECStatus
    304 DSA_NewKeyFromSeed(const PQGParams *params,
    305                   const unsigned char *seed,
    306                   DSAPrivateKey **privKey)
    307 {
    308    SECItem seedItem;
    309    seedItem.data = (unsigned char *)seed;
    310    seedItem.len = PQG_GetLength(&params->subPrime);
    311    return dsa_NewKeyExtended(params, &seedItem, privKey);
    312 }
    313 
    314 static SECStatus
    315 dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
    316               const unsigned char *kbytes)
    317 {
    318    mp_int p, q, g; /* PQG parameters */
    319    mp_int x, k;    /* private key & pseudo-random integer */
    320    mp_int r, s;    /* tuple (r, s) is signature) */
    321    mp_int t;       /* holding tmp values */
    322    mp_int ar;      /* holding blinding values */
    323    mp_digit fuzz;  /* blinding multiplier for q */
    324    mp_err err = MP_OKAY;
    325    SECStatus rv = SECSuccess;
    326    unsigned int dsa_subprime_len, dsa_signature_len, offset;
    327    SECItem localDigest;
    328    unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN];
    329    SECItem t2 = { siBuffer, NULL, 0 };
    330 
    331    /* FIPS-compliance dictates that digest is a SHA hash. */
    332    /* Check args. */
    333    if (!key || !signature || !digest) {
    334        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    335        return SECFailure;
    336    }
    337 
    338    dsa_subprime_len = PQG_GetLength(&key->params.subPrime);
    339    dsa_signature_len = dsa_subprime_len * 2;
    340    if ((signature->len < dsa_signature_len) ||
    341        (digest->len > HASH_LENGTH_MAX) ||
    342        (digest->len < SHA1_LENGTH)) {
    343        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    344        return SECFailure;
    345    }
    346 
    347    /* DSA accepts digests not equal to dsa_subprime_len, if the
    348     * digests are greater, then they are truncated to the size of
    349     * dsa_subprime_len, using the left most bits. If they are less
    350     * then they are padded on the left.*/
    351    PORT_Memset(localDigestData, 0, dsa_subprime_len);
    352    offset = (digest->len < dsa_subprime_len) ? (dsa_subprime_len - digest->len) : 0;
    353    PORT_Memcpy(localDigestData + offset, digest->data,
    354                dsa_subprime_len - offset);
    355    localDigest.data = localDigestData;
    356    localDigest.len = dsa_subprime_len;
    357 
    358    /* Initialize MPI integers. */
    359    MP_DIGITS(&p) = 0;
    360    MP_DIGITS(&q) = 0;
    361    MP_DIGITS(&g) = 0;
    362    MP_DIGITS(&x) = 0;
    363    MP_DIGITS(&k) = 0;
    364    MP_DIGITS(&r) = 0;
    365    MP_DIGITS(&s) = 0;
    366    MP_DIGITS(&t) = 0;
    367    MP_DIGITS(&ar) = 0;
    368    CHECK_MPI_OK(mp_init(&p));
    369    CHECK_MPI_OK(mp_init(&q));
    370    CHECK_MPI_OK(mp_init(&g));
    371    CHECK_MPI_OK(mp_init(&x));
    372    CHECK_MPI_OK(mp_init(&k));
    373    CHECK_MPI_OK(mp_init(&r));
    374    CHECK_MPI_OK(mp_init(&s));
    375    CHECK_MPI_OK(mp_init(&t));
    376    CHECK_MPI_OK(mp_init(&ar));
    377 
    378    /*
    379    ** Convert stored PQG and private key into MPI integers.
    380    */
    381    SECITEM_TO_MPINT(key->params.prime, &p);
    382    SECITEM_TO_MPINT(key->params.subPrime, &q);
    383    SECITEM_TO_MPINT(key->params.base, &g);
    384    SECITEM_TO_MPINT(key->privateValue, &x);
    385    OCTETS_TO_MPINT(kbytes, &k, dsa_subprime_len);
    386 
    387    /* k blinding  create a single value that has the high bit set in
    388     * the mp_digit*/
    389    if (RNG_GenerateGlobalRandomBytes(&fuzz, sizeof(mp_digit)) != SECSuccess) {
    390        PORT_SetError(SEC_ERROR_NEED_RANDOM);
    391        rv = SECFailure;
    392        goto cleanup;
    393    }
    394    fuzz |= 1ULL << ((sizeof(mp_digit) * PR_BITS_PER_BYTE - 1));
    395    /*
    396    ** FIPS 186-1, Section 5, Step 1
    397    **
    398    ** r = (g**k mod p) mod q
    399    */
    400    CHECK_MPI_OK(mp_mul_d(&q, fuzz, &t)); /* t = q*fuzz */
    401    CHECK_MPI_OK(mp_add(&k, &t, &t));     /* t = k+q*fuzz */
    402    /* length of t is now fixed, bits in k have been blinded */
    403    CHECK_MPI_OK(mp_exptmod(&g, &t, &p, &r)); /* r = g**t mod p */
    404    /* r is now g**(k+q*fuzz) == g**k mod p */
    405    CHECK_MPI_OK(mp_mod(&r, &q, &r)); /* r = r mod q    */
    406    /* make sure fuzz is cleared off the stack and not optimized away */
    407    *(volatile mp_digit *)&fuzz = 0;
    408 
    409    /*
    410    ** FIPS 186-1, Section 5, Step 2
    411    **
    412    ** s = (k**-1 * (HASH(M) + x*r)) mod q
    413    */
    414    if (DSA_NewRandom(NULL, &key->params.subPrime, &t2) != SECSuccess) {
    415        PORT_SetError(SEC_ERROR_NEED_RANDOM);
    416        rv = SECFailure;
    417        goto cleanup;
    418    }
    419    SECITEM_TO_MPINT(t2, &t); /* t <-$ Zq */
    420    SECITEM_ZfreeItem(&t2, PR_FALSE);
    421    if (DSA_NewRandom(NULL, &key->params.subPrime, &t2) != SECSuccess) {
    422        PORT_SetError(SEC_ERROR_NEED_RANDOM);
    423        rv = SECFailure;
    424        goto cleanup;
    425    }
    426    SECITEM_TO_MPINT(t2, &ar); /* ar <-$ Zq */
    427    SECITEM_ZfreeItem(&t2, PR_FALSE);
    428 
    429    /* Using mp_invmod on k directly would leak bits from k. */
    430    CHECK_MPI_OK(mp_mul(&k, &ar, &k));       /* k = k * ar */
    431    CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */
    432    /* k is now k*t*ar */
    433    CHECK_MPI_OK(mp_invmod(&k, &q, &k)); /* k = k**-1 mod q */
    434    /* k is now (k*t*ar)**-1 */
    435    CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */
    436    /* k is now (k*ar)**-1 */
    437    SECITEM_TO_MPINT(localDigest, &s); /* s = HASH(M)     */
    438    /* To avoid leaking secret bits here the addition is blinded. */
    439    CHECK_MPI_OK(mp_mul(&x, &ar, &x)); /* x = x * ar */
    440    /* x is now x*ar */
    441    CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x)); /* x = x * r mod q */
    442    /* x is now x*r*ar */
    443    CHECK_MPI_OK(mp_mulmod(&s, &ar, &q, &t)); /* t = s * ar mod q */
    444    /* t is now hash(M)*ar */
    445    CHECK_MPI_OK(mp_add(&t, &x, &s)); /* s = t + x */
    446    /* s is now (HASH(M)+x*r)*ar */
    447    CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s)); /* s = s * k mod q */
    448    /* s is now (HASH(M)+x*r)*ar*(k*ar)**-1 = (k**-1)*(HASH(M)+x*r) */
    449 
    450    /*
    451    ** verify r != 0 and s != 0
    452    ** mentioned as optional in FIPS 186-1.
    453    */
    454    if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) {
    455        PORT_SetError(SEC_ERROR_NEED_RANDOM);
    456        rv = SECFailure;
    457        goto cleanup;
    458    }
    459    /*
    460    ** Step 4
    461    **
    462    ** Signature is tuple (r, s)
    463    */
    464    err = mp_to_fixlen_octets(&r, signature->data, dsa_subprime_len);
    465    if (err < 0)
    466        goto cleanup;
    467    err = mp_to_fixlen_octets(&s, signature->data + dsa_subprime_len,
    468                              dsa_subprime_len);
    469    if (err < 0)
    470        goto cleanup;
    471    err = MP_OKAY;
    472    signature->len = dsa_signature_len;
    473 cleanup:
    474    PORT_SafeZero(localDigestData, DSA_MAX_SUBPRIME_LEN);
    475    mp_clear(&p);
    476    mp_clear(&q);
    477    mp_clear(&g);
    478    mp_clear(&x);
    479    mp_clear(&k);
    480    mp_clear(&r);
    481    mp_clear(&s);
    482    mp_clear(&t);
    483    mp_clear(&ar);
    484    if (err) {
    485        translate_mpi_error(err);
    486        rv = SECFailure;
    487    }
    488    return rv;
    489 }
    490 
    491 /* signature is caller-supplied buffer of at least 40 bytes.
    492 ** On input,  signature->len == size of buffer to hold signature.
    493 **            digest->len    == size of digest.
    494 ** On output, signature->len == size of signature in buffer.
    495 ** Uses a random seed.
    496 */
    497 SECStatus
    498 DSA_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest)
    499 {
    500    SECStatus rv;
    501    int retries = 10;
    502    unsigned char kSeed[DSA_MAX_SUBPRIME_LEN];
    503    unsigned int kSeedLen = 0;
    504    unsigned int i;
    505    unsigned int dsa_subprime_len = PQG_GetLength(&key->params.subPrime);
    506    PRBool good;
    507 
    508    PORT_SetError(0);
    509    do {
    510        rv = dsa_GenerateGlobalRandomBytes(&key->params.subPrime,
    511                                           kSeed, &kSeedLen, sizeof kSeed);
    512        if (rv != SECSuccess)
    513            break;
    514        if (kSeedLen != dsa_subprime_len) {
    515            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    516            rv = SECFailure;
    517            break;
    518        }
    519        /* Disallow a value of 0 for k. */
    520        good = PR_FALSE;
    521        for (i = 0; i < kSeedLen; i++) {
    522            if (kSeed[i] != 0) {
    523                good = PR_TRUE;
    524                break;
    525            }
    526        }
    527        if (!good) {
    528            PORT_SetError(SEC_ERROR_NEED_RANDOM);
    529            rv = SECFailure;
    530            continue;
    531        }
    532        rv = dsa_SignDigest(key, signature, digest, kSeed);
    533    } while (rv != SECSuccess && PORT_GetError() == SEC_ERROR_NEED_RANDOM &&
    534             --retries > 0);
    535    PORT_SafeZero(kSeed, sizeof kSeed);
    536    return rv;
    537 }
    538 
    539 /* For FIPS compliance testing. Seed must be exactly 20 bytes. */
    540 SECStatus
    541 DSA_SignDigestWithSeed(DSAPrivateKey *key,
    542                       SECItem *signature,
    543                       const SECItem *digest,
    544                       const unsigned char *seed)
    545 {
    546    SECStatus rv;
    547    rv = dsa_SignDigest(key, signature, digest, seed);
    548    return rv;
    549 }
    550 
    551 /* signature is caller-supplied buffer of at least 20 bytes.
    552 ** On input,  signature->len == size of buffer to hold signature.
    553 **            digest->len    == size of digest.
    554 */
    555 SECStatus
    556 DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature,
    557                 const SECItem *digest)
    558 {
    559    /* FIPS-compliance dictates that digest is a SHA hash. */
    560    mp_int p, q, g;      /* PQG parameters */
    561    mp_int r_, s_;       /* tuple (r', s') is received signature) */
    562    mp_int u1, u2, v, w; /* intermediate values used in verification */
    563    mp_int y;            /* public key */
    564    mp_err err;
    565    unsigned int dsa_subprime_len, dsa_signature_len, offset;
    566    SECItem localDigest;
    567    unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN];
    568    SECStatus verified = SECFailure;
    569 
    570    /* Check args. */
    571    if (!key || !signature || !digest) {
    572        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    573        return SECFailure;
    574    }
    575 
    576    dsa_subprime_len = PQG_GetLength(&key->params.subPrime);
    577    dsa_signature_len = dsa_subprime_len * 2;
    578    if ((signature->len != dsa_signature_len) ||
    579        (digest->len > HASH_LENGTH_MAX) ||
    580        (digest->len < SHA1_LENGTH)) {
    581        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    582        return SECFailure;
    583    }
    584 
    585    /* DSA accepts digests not equal to dsa_subprime_len, if the
    586     * digests are greater, than they are truncated to the size of
    587     * dsa_subprime_len, using the left most bits. If they are less
    588     * then they are padded on the left.*/
    589    PORT_Memset(localDigestData, 0, dsa_subprime_len);
    590    offset = (digest->len < dsa_subprime_len) ? (dsa_subprime_len - digest->len) : 0;
    591    PORT_Memcpy(localDigestData + offset, digest->data,
    592                dsa_subprime_len - offset);
    593    localDigest.data = localDigestData;
    594    localDigest.len = dsa_subprime_len;
    595 
    596    /* Initialize MPI integers. */
    597    MP_DIGITS(&p) = 0;
    598    MP_DIGITS(&q) = 0;
    599    MP_DIGITS(&g) = 0;
    600    MP_DIGITS(&y) = 0;
    601    MP_DIGITS(&r_) = 0;
    602    MP_DIGITS(&s_) = 0;
    603    MP_DIGITS(&u1) = 0;
    604    MP_DIGITS(&u2) = 0;
    605    MP_DIGITS(&v) = 0;
    606    MP_DIGITS(&w) = 0;
    607    CHECK_MPI_OK(mp_init(&p));
    608    CHECK_MPI_OK(mp_init(&q));
    609    CHECK_MPI_OK(mp_init(&g));
    610    CHECK_MPI_OK(mp_init(&y));
    611    CHECK_MPI_OK(mp_init(&r_));
    612    CHECK_MPI_OK(mp_init(&s_));
    613    CHECK_MPI_OK(mp_init(&u1));
    614    CHECK_MPI_OK(mp_init(&u2));
    615    CHECK_MPI_OK(mp_init(&v));
    616    CHECK_MPI_OK(mp_init(&w));
    617    /*
    618    ** Convert stored PQG and public key into MPI integers.
    619    */
    620    SECITEM_TO_MPINT(key->params.prime, &p);
    621    SECITEM_TO_MPINT(key->params.subPrime, &q);
    622    SECITEM_TO_MPINT(key->params.base, &g);
    623    SECITEM_TO_MPINT(key->publicValue, &y);
    624    /*
    625    ** Convert received signature (r', s') into MPI integers.
    626    */
    627    OCTETS_TO_MPINT(signature->data, &r_, dsa_subprime_len);
    628    OCTETS_TO_MPINT(signature->data + dsa_subprime_len, &s_, dsa_subprime_len);
    629    /*
    630    ** Verify that 0 < r' < q and 0 < s' < q
    631    */
    632    if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
    633        mp_cmp(&r_, &q) >= 0 || mp_cmp(&s_, &q) >= 0) {
    634        /* err is zero here. */
    635        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
    636        goto cleanup; /* will return verified == SECFailure */
    637    }
    638    /*
    639    ** FIPS 186-1, Section 6, Step 1
    640    **
    641    ** w = (s')**-1 mod q
    642    */
    643    CHECK_MPI_OK(mp_invmod(&s_, &q, &w)); /* w = (s')**-1 mod q */
    644    /*
    645    ** FIPS 186-1, Section 6, Step 2
    646    **
    647    ** u1 = ((Hash(M')) * w) mod q
    648    */
    649    SECITEM_TO_MPINT(localDigest, &u1);        /* u1 = HASH(M')     */
    650    CHECK_MPI_OK(mp_mulmod(&u1, &w, &q, &u1)); /* u1 = u1 * w mod q */
    651    /*
    652    ** FIPS 186-1, Section 6, Step 3
    653    **
    654    ** u2 = ((r') * w) mod q
    655    */
    656    CHECK_MPI_OK(mp_mulmod(&r_, &w, &q, &u2));
    657    /*
    658    ** FIPS 186-1, Section 6, Step 4
    659    **
    660    ** v = ((g**u1 * y**u2) mod p) mod q
    661    */
    662    CHECK_MPI_OK(mp_exptmod(&g, &u1, &p, &g)); /* g = g**u1 mod p */
    663    CHECK_MPI_OK(mp_exptmod(&y, &u2, &p, &y)); /* y = y**u2 mod p */
    664    CHECK_MPI_OK(mp_mulmod(&g, &y, &p, &v));   /* v = g * y mod p */
    665    CHECK_MPI_OK(mp_mod(&v, &q, &v));          /* v = v mod q     */
    666    /*
    667    ** Verification:  v == r'
    668    */
    669    if (mp_cmp(&v, &r_)) {
    670        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
    671        verified = SECFailure; /* Signature failed to verify. */
    672    } else {
    673        verified = SECSuccess; /* Signature verified. */
    674    }
    675 cleanup:
    676    PORT_SafeZero(localDigestData, sizeof localDigestData);
    677    mp_clear(&p);
    678    mp_clear(&q);
    679    mp_clear(&g);
    680    mp_clear(&y);
    681    mp_clear(&r_);
    682    mp_clear(&s_);
    683    mp_clear(&u1);
    684    mp_clear(&u2);
    685    mp_clear(&v);
    686    mp_clear(&w);
    687    if (err) {
    688        translate_mpi_error(err);
    689    }
    690    return verified;
    691 }