tor-browser

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

jpake.c (13609B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifdef FREEBL_NO_DEPEND
      6 #include "stubs.h"
      7 #endif
      8 
      9 #include "blapi.h"
     10 #include "secerr.h"
     11 #include "secitem.h"
     12 #include "secmpi.h"
     13 
     14 /* Hash an item's length and then its value. Only items smaller than 2^16 bytes
     15 * are allowed. Lengths are hashed in network byte order. This is designed
     16 * to match the OpenSSL J-PAKE implementation.
     17 */
     18 static mp_err
     19 hashSECItem(HASHContext *hash, const SECItem *it)
     20 {
     21    unsigned char length[2];
     22 
     23    if (it->len > 0xffff)
     24        return MP_BADARG;
     25 
     26    length[0] = (unsigned char)(it->len >> 8);
     27    length[1] = (unsigned char)(it->len);
     28    hash->hashobj->update(hash->hash_context, length, 2);
     29    hash->hashobj->update(hash->hash_context, it->data, it->len);
     30    return MP_OKAY;
     31 }
     32 
     33 /* Hash all public components of the signature, each prefixed with its
     34   length, and then convert the hash to an mp_int. */
     35 static mp_err
     36 hashPublicParams(HASH_HashType hashType, const SECItem *g,
     37                 const SECItem *gv, const SECItem *gx,
     38                 const SECItem *signerID, mp_int *h)
     39 {
     40    mp_err err;
     41    unsigned char hBuf[HASH_LENGTH_MAX];
     42    SECItem hItem;
     43    HASHContext hash;
     44 
     45    hash.hashobj = HASH_GetRawHashObject(hashType);
     46    if (hash.hashobj == NULL || hash.hashobj->length > sizeof hBuf) {
     47        return MP_BADARG;
     48    }
     49    hash.hash_context = hash.hashobj->create();
     50    if (hash.hash_context == NULL) {
     51        return MP_MEM;
     52    }
     53 
     54    hItem.data = hBuf;
     55    hItem.len = hash.hashobj->length;
     56 
     57    hash.hashobj->begin(hash.hash_context);
     58    CHECK_MPI_OK(hashSECItem(&hash, g));
     59    CHECK_MPI_OK(hashSECItem(&hash, gv));
     60    CHECK_MPI_OK(hashSECItem(&hash, gx));
     61    CHECK_MPI_OK(hashSECItem(&hash, signerID));
     62    hash.hashobj->end(hash.hash_context, hItem.data, &hItem.len,
     63                      sizeof hBuf);
     64    SECITEM_TO_MPINT(hItem, h);
     65 
     66 cleanup:
     67    if (hash.hash_context != NULL) {
     68        hash.hashobj->destroy(hash.hash_context, PR_TRUE);
     69    }
     70 
     71    return err;
     72 }
     73 
     74 /* Generate a Schnorr signature for round 1 or round 2 */
     75 SECStatus
     76 JPAKE_Sign(PLArenaPool *arena, const PQGParams *pqg, HASH_HashType hashType,
     77           const SECItem *signerID, const SECItem *x,
     78           const SECItem *testRandom, const SECItem *gxIn, SECItem *gxOut,
     79           SECItem *gv, SECItem *r)
     80 {
     81    SECStatus rv = SECSuccess;
     82    mp_err err;
     83    mp_int p;
     84    mp_int q;
     85    mp_int g;
     86    mp_int X;
     87    mp_int GX;
     88    mp_int V;
     89    mp_int GV;
     90    mp_int h;
     91    mp_int tmp;
     92    mp_int R;
     93    SECItem v;
     94 
     95    if (!arena ||
     96        !pqg || !pqg->prime.data || pqg->prime.len == 0 ||
     97        !pqg->subPrime.data || pqg->subPrime.len == 0 ||
     98        !pqg->base.data || pqg->base.len == 0 ||
     99        !signerID || !signerID->data || signerID->len == 0 ||
    100        !x || !x->data || x->len == 0 ||
    101        (testRandom && (!testRandom->data || testRandom->len == 0)) ||
    102        (gxIn == NULL && (!gxOut || gxOut->data != NULL)) ||
    103        (gxIn != NULL && (!gxIn->data || gxIn->len == 0 || gxOut != NULL)) ||
    104        !gv || gv->data != NULL ||
    105        !r || r->data != NULL) {
    106        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    107        return SECFailure;
    108    }
    109 
    110    MP_DIGITS(&p) = 0;
    111    MP_DIGITS(&q) = 0;
    112    MP_DIGITS(&g) = 0;
    113    MP_DIGITS(&X) = 0;
    114    MP_DIGITS(&GX) = 0;
    115    MP_DIGITS(&V) = 0;
    116    MP_DIGITS(&GV) = 0;
    117    MP_DIGITS(&h) = 0;
    118    MP_DIGITS(&tmp) = 0;
    119    MP_DIGITS(&R) = 0;
    120 
    121    CHECK_MPI_OK(mp_init(&p));
    122    CHECK_MPI_OK(mp_init(&q));
    123    CHECK_MPI_OK(mp_init(&g));
    124    CHECK_MPI_OK(mp_init(&X));
    125    CHECK_MPI_OK(mp_init(&GX));
    126    CHECK_MPI_OK(mp_init(&V));
    127    CHECK_MPI_OK(mp_init(&GV));
    128    CHECK_MPI_OK(mp_init(&h));
    129    CHECK_MPI_OK(mp_init(&tmp));
    130    CHECK_MPI_OK(mp_init(&R));
    131 
    132    SECITEM_TO_MPINT(pqg->prime, &p);
    133    SECITEM_TO_MPINT(pqg->subPrime, &q);
    134    SECITEM_TO_MPINT(pqg->base, &g);
    135    SECITEM_TO_MPINT(*x, &X);
    136 
    137    /* gx = g^x */
    138    if (gxIn == NULL) {
    139        CHECK_MPI_OK(mp_exptmod(&g, &X, &p, &GX));
    140        MPINT_TO_SECITEM(&GX, gxOut, arena);
    141        gxIn = gxOut;
    142    } else {
    143        SECITEM_TO_MPINT(*gxIn, &GX);
    144    }
    145 
    146    /* v is a random value in the q subgroup */
    147    if (testRandom == NULL) {
    148        v.data = NULL;
    149        rv = DSA_NewRandom(arena, &pqg->subPrime, &v);
    150        if (rv != SECSuccess) {
    151            goto cleanup;
    152        }
    153    } else {
    154        v.data = testRandom->data;
    155        v.len = testRandom->len;
    156    }
    157    SECITEM_TO_MPINT(v, &V);
    158 
    159    /* gv = g^v (mod q), random v, 1 <= v < q */
    160    CHECK_MPI_OK(mp_exptmod(&g, &V, &p, &GV));
    161    MPINT_TO_SECITEM(&GV, gv, arena);
    162 
    163    /* h = H(g, gv, gx, signerID) */
    164    CHECK_MPI_OK(hashPublicParams(hashType, &pqg->base, gv, gxIn, signerID,
    165                                  &h));
    166 
    167    /* r = v - x*h (mod q) */
    168    CHECK_MPI_OK(mp_mulmod(&X, &h, &q, &tmp));
    169    CHECK_MPI_OK(mp_submod(&V, &tmp, &q, &R));
    170    MPINT_TO_SECITEM(&R, r, arena);
    171 
    172 cleanup:
    173    mp_clear(&p);
    174    mp_clear(&q);
    175    mp_clear(&g);
    176    mp_clear(&X);
    177    mp_clear(&GX);
    178    mp_clear(&V);
    179    mp_clear(&GV);
    180    mp_clear(&h);
    181    mp_clear(&tmp);
    182    mp_clear(&R);
    183 
    184    if (rv == SECSuccess && err != MP_OKAY) {
    185        MP_TO_SEC_ERROR(err);
    186        rv = SECFailure;
    187    }
    188    return rv;
    189 }
    190 
    191 /* Verify a Schnorr signature generated by the peer in round 1 or round 2. */
    192 SECStatus
    193 JPAKE_Verify(PLArenaPool *arena, const PQGParams *pqg, HASH_HashType hashType,
    194             const SECItem *signerID, const SECItem *peerID,
    195             const SECItem *gx, const SECItem *gv, const SECItem *r)
    196 {
    197    SECStatus rv = SECSuccess;
    198    mp_err err;
    199    mp_int p;
    200    mp_int q;
    201    mp_int g;
    202    mp_int p_minus_1;
    203    mp_int GX;
    204    mp_int h;
    205    mp_int one;
    206    mp_int R;
    207    mp_int gr;
    208    mp_int gxh;
    209    mp_int gr_gxh;
    210    SECItem calculated;
    211 
    212    if (!arena ||
    213        !pqg || !pqg->prime.data || pqg->prime.len == 0 ||
    214        !pqg->subPrime.data || pqg->subPrime.len == 0 ||
    215        !pqg->base.data || pqg->base.len == 0 ||
    216        !signerID || !signerID->data || signerID->len == 0 ||
    217        !peerID || !peerID->data || peerID->len == 0 ||
    218        !gx || !gx->data || gx->len == 0 ||
    219        !gv || !gv->data || gv->len == 0 ||
    220        !r || !r->data || r->len == 0 ||
    221        SECITEM_CompareItem(signerID, peerID) == SECEqual) {
    222        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    223        return SECFailure;
    224    }
    225 
    226    MP_DIGITS(&p) = 0;
    227    MP_DIGITS(&q) = 0;
    228    MP_DIGITS(&g) = 0;
    229    MP_DIGITS(&p_minus_1) = 0;
    230    MP_DIGITS(&GX) = 0;
    231    MP_DIGITS(&h) = 0;
    232    MP_DIGITS(&one) = 0;
    233    MP_DIGITS(&R) = 0;
    234    MP_DIGITS(&gr) = 0;
    235    MP_DIGITS(&gxh) = 0;
    236    MP_DIGITS(&gr_gxh) = 0;
    237    calculated.data = NULL;
    238 
    239    CHECK_MPI_OK(mp_init(&p));
    240    CHECK_MPI_OK(mp_init(&q));
    241    CHECK_MPI_OK(mp_init(&g));
    242    CHECK_MPI_OK(mp_init(&p_minus_1));
    243    CHECK_MPI_OK(mp_init(&GX));
    244    CHECK_MPI_OK(mp_init(&h));
    245    CHECK_MPI_OK(mp_init(&one));
    246    CHECK_MPI_OK(mp_init(&R));
    247    CHECK_MPI_OK(mp_init(&gr));
    248    CHECK_MPI_OK(mp_init(&gxh));
    249    CHECK_MPI_OK(mp_init(&gr_gxh));
    250 
    251    SECITEM_TO_MPINT(pqg->prime, &p);
    252    SECITEM_TO_MPINT(pqg->subPrime, &q);
    253    SECITEM_TO_MPINT(pqg->base, &g);
    254    SECITEM_TO_MPINT(*gx, &GX);
    255    SECITEM_TO_MPINT(*r, &R);
    256 
    257    CHECK_MPI_OK(mp_sub_d(&p, 1, &p_minus_1));
    258    CHECK_MPI_OK(mp_exptmod(&GX, &q, &p, &one));
    259    /* Check g^x is in [1, p-2], R is in [0, q-1], and (g^x)^q mod p == 1 */
    260    if (!(mp_cmp_z(&GX) > 0 &&
    261          mp_cmp(&GX, &p_minus_1) < 0 &&
    262          mp_cmp(&R, &q) < 0 &&
    263          mp_cmp_d(&one, 1) == 0)) {
    264        goto badSig;
    265    }
    266 
    267    CHECK_MPI_OK(hashPublicParams(hashType, &pqg->base, gv, gx, peerID,
    268                                  &h));
    269 
    270    /* Calculate g^v = g^r * g^x^h */
    271    CHECK_MPI_OK(mp_exptmod(&g, &R, &p, &gr));
    272    CHECK_MPI_OK(mp_exptmod(&GX, &h, &p, &gxh));
    273    CHECK_MPI_OK(mp_mulmod(&gr, &gxh, &p, &gr_gxh));
    274 
    275    /* Compare calculated g^v to given g^v */
    276    MPINT_TO_SECITEM(&gr_gxh, &calculated, arena);
    277    if (calculated.len == gv->len &&
    278        NSS_SecureMemcmp(calculated.data, gv->data, calculated.len) == 0) {
    279        rv = SECSuccess;
    280    } else {
    281    badSig:
    282        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
    283        rv = SECFailure;
    284    }
    285 
    286 cleanup:
    287    mp_clear(&p);
    288    mp_clear(&q);
    289    mp_clear(&g);
    290    mp_clear(&p_minus_1);
    291    mp_clear(&GX);
    292    mp_clear(&h);
    293    mp_clear(&one);
    294    mp_clear(&R);
    295    mp_clear(&gr);
    296    mp_clear(&gxh);
    297    mp_clear(&gr_gxh);
    298 
    299    if (rv == SECSuccess && err != MP_OKAY) {
    300        MP_TO_SEC_ERROR(err);
    301        rv = SECFailure;
    302    }
    303    return rv;
    304 }
    305 
    306 /* Calculate base = gx1*gx3*gx4 (mod p), i.e. g^(x1+x3+x4) (mod p) */
    307 static mp_err
    308 jpake_Round2Base(const SECItem *gx1, const SECItem *gx3,
    309                 const SECItem *gx4, const mp_int *p, mp_int *base)
    310 {
    311    mp_err err;
    312    mp_int GX1;
    313    mp_int GX3;
    314    mp_int GX4;
    315    mp_int tmp;
    316 
    317    MP_DIGITS(&GX1) = 0;
    318    MP_DIGITS(&GX3) = 0;
    319    MP_DIGITS(&GX4) = 0;
    320    MP_DIGITS(&tmp) = 0;
    321 
    322    CHECK_MPI_OK(mp_init(&GX1));
    323    CHECK_MPI_OK(mp_init(&GX3));
    324    CHECK_MPI_OK(mp_init(&GX4));
    325    CHECK_MPI_OK(mp_init(&tmp));
    326 
    327    SECITEM_TO_MPINT(*gx1, &GX1);
    328    SECITEM_TO_MPINT(*gx3, &GX3);
    329    SECITEM_TO_MPINT(*gx4, &GX4);
    330 
    331    /* In round 2, the peer/attacker sends us g^x3 and g^x4 and the protocol
    332       requires that these values are distinct. */
    333    if (mp_cmp(&GX3, &GX4) == 0) {
    334        return MP_BADARG;
    335    }
    336 
    337    CHECK_MPI_OK(mp_mul(&GX1, &GX3, &tmp));
    338    CHECK_MPI_OK(mp_mul(&tmp, &GX4, &tmp));
    339    CHECK_MPI_OK(mp_mod(&tmp, p, base));
    340 
    341 cleanup:
    342    mp_clear(&GX1);
    343    mp_clear(&GX3);
    344    mp_clear(&GX4);
    345    mp_clear(&tmp);
    346    return err;
    347 }
    348 
    349 SECStatus
    350 JPAKE_Round2(PLArenaPool *arena,
    351             const SECItem *p, const SECItem *q, const SECItem *gx1,
    352             const SECItem *gx3, const SECItem *gx4, SECItem *base,
    353             const SECItem *x2, const SECItem *s, SECItem *x2s)
    354 {
    355    mp_err err;
    356    mp_int P;
    357    mp_int Q;
    358    mp_int X2;
    359    mp_int S;
    360    mp_int result;
    361 
    362    if (!arena ||
    363        !p || !p->data || p->len == 0 ||
    364        !q || !q->data || q->len == 0 ||
    365        !gx1 || !gx1->data || gx1->len == 0 ||
    366        !gx3 || !gx3->data || gx3->len == 0 ||
    367        !gx4 || !gx4->data || gx4->len == 0 ||
    368        !base || base->data != NULL ||
    369        (x2s != NULL && (x2s->data != NULL ||
    370                         !x2 || !x2->data || x2->len == 0 ||
    371                         !s || !s->data || s->len == 0))) {
    372        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    373        return SECFailure;
    374    }
    375 
    376    MP_DIGITS(&P) = 0;
    377    MP_DIGITS(&Q) = 0;
    378    MP_DIGITS(&X2) = 0;
    379    MP_DIGITS(&S) = 0;
    380    MP_DIGITS(&result) = 0;
    381 
    382    CHECK_MPI_OK(mp_init(&P));
    383    CHECK_MPI_OK(mp_init(&Q));
    384    CHECK_MPI_OK(mp_init(&result));
    385 
    386    if (x2s != NULL) {
    387        CHECK_MPI_OK(mp_init(&X2));
    388        CHECK_MPI_OK(mp_init(&S));
    389 
    390        SECITEM_TO_MPINT(*q, &Q);
    391        SECITEM_TO_MPINT(*x2, &X2);
    392 
    393        SECITEM_TO_MPINT(*s, &S);
    394        /* S must be in [1, Q-1] */
    395        if (mp_cmp_z(&S) <= 0 || mp_cmp(&S, &Q) >= 0) {
    396            err = MP_BADARG;
    397            goto cleanup;
    398        }
    399 
    400        CHECK_MPI_OK(mp_mulmod(&X2, &S, &Q, &result));
    401        MPINT_TO_SECITEM(&result, x2s, arena);
    402    }
    403 
    404    SECITEM_TO_MPINT(*p, &P);
    405    CHECK_MPI_OK(jpake_Round2Base(gx1, gx3, gx4, &P, &result));
    406    MPINT_TO_SECITEM(&result, base, arena);
    407 
    408 cleanup:
    409    mp_clear(&P);
    410    mp_clear(&Q);
    411    mp_clear(&X2);
    412    mp_clear(&S);
    413    mp_clear(&result);
    414 
    415    if (err != MP_OKAY) {
    416        MP_TO_SEC_ERROR(err);
    417        return SECFailure;
    418    }
    419    return SECSuccess;
    420 }
    421 
    422 SECStatus
    423 JPAKE_Final(PLArenaPool *arena, const SECItem *p, const SECItem *q,
    424            const SECItem *x2, const SECItem *gx4, const SECItem *x2s,
    425            const SECItem *B, SECItem *K)
    426 {
    427    mp_err err;
    428    mp_int P;
    429    mp_int Q;
    430    mp_int tmp;
    431    mp_int exponent;
    432    mp_int divisor;
    433    mp_int base;
    434 
    435    if (!arena ||
    436        !p || !p->data || p->len == 0 ||
    437        !q || !q->data || q->len == 0 ||
    438        !x2 || !x2->data || x2->len == 0 ||
    439        !gx4 || !gx4->data || gx4->len == 0 ||
    440        !x2s || !x2s->data || x2s->len == 0 ||
    441        !B || !B->data || B->len == 0 ||
    442        !K || K->data != NULL) {
    443        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    444        return SECFailure;
    445    }
    446 
    447    MP_DIGITS(&P) = 0;
    448    MP_DIGITS(&Q) = 0;
    449    MP_DIGITS(&tmp) = 0;
    450    MP_DIGITS(&exponent) = 0;
    451    MP_DIGITS(&divisor) = 0;
    452    MP_DIGITS(&base) = 0;
    453 
    454    CHECK_MPI_OK(mp_init(&P));
    455    CHECK_MPI_OK(mp_init(&Q));
    456    CHECK_MPI_OK(mp_init(&tmp));
    457    CHECK_MPI_OK(mp_init(&exponent));
    458    CHECK_MPI_OK(mp_init(&divisor));
    459    CHECK_MPI_OK(mp_init(&base));
    460 
    461    /* exponent = -x2s (mod q) */
    462    SECITEM_TO_MPINT(*q, &Q);
    463    SECITEM_TO_MPINT(*x2s, &tmp);
    464    /*  q == 0 (mod q), so q - x2s == -x2s (mod q) */
    465    CHECK_MPI_OK(mp_sub(&Q, &tmp, &exponent));
    466 
    467    /* divisor = gx4^-x2s = 1/(gx4^x2s) (mod p) */
    468    SECITEM_TO_MPINT(*p, &P);
    469    SECITEM_TO_MPINT(*gx4, &tmp);
    470    CHECK_MPI_OK(mp_exptmod(&tmp, &exponent, &P, &divisor));
    471 
    472    /* base = B*divisor = B/(gx4^x2s) (mod p) */
    473    SECITEM_TO_MPINT(*B, &tmp);
    474    CHECK_MPI_OK(mp_mulmod(&divisor, &tmp, &P, &base));
    475 
    476    /* tmp = base^x2 (mod p) */
    477    SECITEM_TO_MPINT(*x2, &exponent);
    478    CHECK_MPI_OK(mp_exptmod(&base, &exponent, &P, &tmp));
    479 
    480    MPINT_TO_SECITEM(&tmp, K, arena);
    481 
    482 cleanup:
    483    mp_clear(&P);
    484    mp_clear(&Q);
    485    mp_clear(&tmp);
    486    mp_clear(&exponent);
    487    mp_clear(&divisor);
    488    mp_clear(&base);
    489 
    490    if (err != MP_OKAY) {
    491        MP_TO_SEC_ERROR(err);
    492        return SECFailure;
    493    }
    494    return SECSuccess;
    495 }