security/nss/lib/freebl/jpake.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     5 #ifdef FREEBL_NO_DEPEND
     6 #include "stubs.h"
     7 #endif
     9 #include "blapi.h"
    10 #include "secerr.h"
    11 #include "secitem.h"
    12 #include "secmpi.h"
    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];
    23     if (it->len > 0xffff)
    24         return MP_BADARG;
    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 }
    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;
    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     }
    54     hItem.data = hBuf;
    55     hItem.len = hash.hashobj->length;
    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);
    66 cleanup:
    67     if (hash.hash_context != NULL) {
    68         hash.hashobj->destroy(hash.hash_context, PR_TRUE);
    69     }
    71     return err;
    72 }
    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;
    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     }
   111     MP_DIGITS(&p) = 0;
   112     MP_DIGITS(&q) = 0;
   113     MP_DIGITS(&g) = 0;
   114     MP_DIGITS(&X) = 0;
   115     MP_DIGITS(&GX) = 0;
   116     MP_DIGITS(&V) = 0;
   117     MP_DIGITS(&GV) = 0;
   118     MP_DIGITS(&h) = 0;
   119     MP_DIGITS(&tmp) = 0;
   120     MP_DIGITS(&R) = 0;
   122     CHECK_MPI_OK( mp_init(&p) );
   123     CHECK_MPI_OK( mp_init(&q) );
   124     CHECK_MPI_OK( mp_init(&g) );
   125     CHECK_MPI_OK( mp_init(&X) );
   126     CHECK_MPI_OK( mp_init(&GX) );
   127     CHECK_MPI_OK( mp_init(&V) );
   128     CHECK_MPI_OK( mp_init(&GV) );
   129     CHECK_MPI_OK( mp_init(&h) );
   130     CHECK_MPI_OK( mp_init(&tmp) );
   131     CHECK_MPI_OK( mp_init(&R) );
   133     SECITEM_TO_MPINT(pqg->prime, &p);
   134     SECITEM_TO_MPINT(pqg->subPrime, &q);
   135     SECITEM_TO_MPINT(pqg->base, &g);
   136     SECITEM_TO_MPINT(*x,  &X);
   138     /* gx = g^x */
   139     if (gxIn == NULL) {
   140         CHECK_MPI_OK( mp_exptmod(&g, &X, &p, &GX) );
   141         MPINT_TO_SECITEM(&GX, gxOut, arena);
   142         gxIn = gxOut;
   143     } else {
   144         SECITEM_TO_MPINT(*gxIn, &GX);
   145     }
   147     /* v is a random value in the q subgroup */
   148     if (testRandom == NULL) {
   149         v.data = NULL;
   150         rv = DSA_NewRandom(arena, &pqg->subPrime, &v);
   151         if (rv != SECSuccess) {
   152             goto cleanup;
   153         }
   154     } else {
   155         v.data = testRandom->data;
   156         v.len = testRandom->len;
   157     }
   158     SECITEM_TO_MPINT(v, &V);
   160     /* gv = g^v (mod q), random v, 1 <= v < q */
   161     CHECK_MPI_OK( mp_exptmod(&g, &V, &p, &GV) );
   162     MPINT_TO_SECITEM(&GV, gv, arena);
   164     /* h = H(g, gv, gx, signerID) */
   165     CHECK_MPI_OK( hashPublicParams(hashType, &pqg->base, gv, gxIn, signerID,
   166                                    &h) );
   168     /* r = v - x*h (mod q) */
   169     CHECK_MPI_OK( mp_mulmod(&X, &h, &q, &tmp) );
   170     CHECK_MPI_OK( mp_submod(&V, &tmp, &q, &R) );
   171     MPINT_TO_SECITEM(&R, r, arena);
   173 cleanup:
   174     mp_clear(&p);
   175     mp_clear(&q);
   176     mp_clear(&g);
   177     mp_clear(&X);
   178     mp_clear(&GX);
   179     mp_clear(&V);
   180     mp_clear(&GV);
   181     mp_clear(&h);
   182     mp_clear(&tmp);
   183     mp_clear(&R);
   185     if (rv == SECSuccess && err != MP_OKAY) {
   186         MP_TO_SEC_ERROR(err);
   187         rv = SECFailure;
   188     }
   189     return rv;
   190 }
   192 /* Verify a Schnorr signature generated by the peer in round 1 or round 2. */
   193 SECStatus
   194 JPAKE_Verify(PLArenaPool * arena, const PQGParams * pqg, HASH_HashType hashType,
   195              const SECItem * signerID, const SECItem * peerID,
   196              const SECItem * gx, const SECItem * gv, const SECItem * r)
   197 {
   198     SECStatus rv = SECSuccess;
   199     mp_err err;
   200     mp_int p;
   201     mp_int q;
   202     mp_int g;
   203     mp_int p_minus_1;
   204     mp_int GX;
   205     mp_int h;
   206     mp_int one;
   207     mp_int R;
   208     mp_int gr;
   209     mp_int gxh;
   210     mp_int gr_gxh;
   211     SECItem calculated;
   213     if (!arena    ||
   214         !pqg      || !pqg->prime.data    || pqg->prime.len == 0 ||
   215                      !pqg->subPrime.data || pqg->subPrime.len == 0 ||
   216                      !pqg->base.data     || pqg->base.len == 0 ||
   217         !signerID || !signerID->data  || signerID->len == 0 ||
   218         !peerID   || !peerID->data    || peerID->len == 0 ||
   219         !gx       || !gx->data        || gx->len == 0 ||
   220         !gv       || !gv->data        || gv->len == 0 ||
   221         !r        || !r->data         || r->len == 0 ||
   222         SECITEM_CompareItem(signerID, peerID) == SECEqual) {
   223         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   224         return SECFailure;
   225     }
   227     MP_DIGITS(&p) = 0;
   228     MP_DIGITS(&q) = 0;
   229     MP_DIGITS(&g) = 0;
   230     MP_DIGITS(&p_minus_1) = 0;
   231     MP_DIGITS(&GX) = 0;
   232     MP_DIGITS(&h) = 0;
   233     MP_DIGITS(&one) = 0;
   234     MP_DIGITS(&R) = 0;
   235     MP_DIGITS(&gr) = 0;
   236     MP_DIGITS(&gxh) = 0;
   237     MP_DIGITS(&gr_gxh) = 0;
   238     calculated.data = NULL;
   240     CHECK_MPI_OK( mp_init(&p) );
   241     CHECK_MPI_OK( mp_init(&q) );
   242     CHECK_MPI_OK( mp_init(&g) );
   243     CHECK_MPI_OK( mp_init(&p_minus_1) );
   244     CHECK_MPI_OK( mp_init(&GX) );
   245     CHECK_MPI_OK( mp_init(&h) );
   246     CHECK_MPI_OK( mp_init(&one) );
   247     CHECK_MPI_OK( mp_init(&R) );
   248     CHECK_MPI_OK( mp_init(&gr) );
   249     CHECK_MPI_OK( mp_init(&gxh) );
   250     CHECK_MPI_OK( mp_init(&gr_gxh) );
   252     SECITEM_TO_MPINT(pqg->prime, &p);
   253     SECITEM_TO_MPINT(pqg->subPrime, &q);
   254     SECITEM_TO_MPINT(pqg->base, &g);
   255     SECITEM_TO_MPINT(*gx, &GX);
   256     SECITEM_TO_MPINT(*r, &R);
   258     CHECK_MPI_OK( mp_sub_d(&p, 1, &p_minus_1) );
   259     CHECK_MPI_OK( mp_exptmod(&GX, &q, &p, &one) );
   260     /* Check g^x is in [1, p-2], R is in [0, q-1], and (g^x)^q mod p == 1 */
   261     if (!(mp_cmp_z(&GX) > 0 && 
   262           mp_cmp(&GX, &p_minus_1) < 0 && 
   263           mp_cmp(&R, &q) < 0 &&
   264           mp_cmp_d(&one, 1) == 0)) {
   265         goto badSig;
   266     }
   268     CHECK_MPI_OK( hashPublicParams(hashType, &pqg->base, gv, gx, peerID,
   269                                    &h) );
   271     /* Calculate g^v = g^r * g^x^h */
   272     CHECK_MPI_OK( mp_exptmod(&g, &R, &p, &gr) );
   273     CHECK_MPI_OK( mp_exptmod(&GX, &h, &p, &gxh) );
   274     CHECK_MPI_OK( mp_mulmod(&gr, &gxh, &p, &gr_gxh) );
   276     /* Compare calculated g^v to given g^v */
   277     MPINT_TO_SECITEM(&gr_gxh, &calculated, arena);
   278     if (calculated.len == gv->len &&
   279         NSS_SecureMemcmp(calculated.data, gv->data, calculated.len) == 0) {
   280         rv = SECSuccess;
   281     } else {
   282 badSig: PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
   283         rv = SECFailure;
   284     }
   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);
   299     if (rv == SECSuccess && err != MP_OKAY) {
   300         MP_TO_SEC_ERROR(err);
   301         rv = SECFailure;
   302     }
   303     return rv;
   304 }
   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;
   317     MP_DIGITS(&GX1) = 0;
   318     MP_DIGITS(&GX3) = 0;
   319     MP_DIGITS(&GX4) = 0;
   320     MP_DIGITS(&tmp) = 0;
   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) );
   327     SECITEM_TO_MPINT(*gx1, &GX1);
   328     SECITEM_TO_MPINT(*gx3, &GX3);
   329     SECITEM_TO_MPINT(*gx4, &GX4);
   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     }
   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) );
   341 cleanup:
   342     mp_clear(&GX1);
   343     mp_clear(&GX3);
   344     mp_clear(&GX4);
   345     mp_clear(&tmp);
   346     return err;
   347 }
   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;
   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     }
   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;
   382     CHECK_MPI_OK( mp_init(&P) );
   383     CHECK_MPI_OK( mp_init(&Q) );
   384     CHECK_MPI_OK( mp_init(&result) );
   386     if (x2s != NULL) {
   387         CHECK_MPI_OK( mp_init(&X2) );
   388         CHECK_MPI_OK( mp_init(&S) );
   390         SECITEM_TO_MPINT(*q, &Q);
   391         SECITEM_TO_MPINT(*x2, &X2);
   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         }
   400         CHECK_MPI_OK( mp_mulmod(&X2, &S, &Q, &result) );
   401         MPINT_TO_SECITEM(&result, x2s, arena);
   402     }
   404     SECITEM_TO_MPINT(*p, &P);
   405     CHECK_MPI_OK( jpake_Round2Base(gx1, gx3, gx4, &P, &result) );
   406     MPINT_TO_SECITEM(&result, base, arena);
   408 cleanup:
   409     mp_clear(&P);
   410     mp_clear(&Q);
   411     mp_clear(&X2);
   412     mp_clear(&S);
   413     mp_clear(&result);
   415     if (err != MP_OKAY) {
   416         MP_TO_SEC_ERROR(err);
   417         return SECFailure;
   418     }
   419     return SECSuccess;
   420 }
   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;
   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     }
   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;
   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) );
   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) );
   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) );
   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) );
   476     /* tmp = base^x2 (mod p) */
   477     SECITEM_TO_MPINT(*x2, &exponent);
   478     CHECK_MPI_OK( mp_exptmod(&base, &exponent, &P, &tmp) );
   480     MPINT_TO_SECITEM(&tmp, K, arena);
   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);
   490     if (err != MP_OKAY) {
   491         MP_TO_SEC_ERROR(err);
   492         return SECFailure;
   493     }
   494     return SECSuccess;
   495 }

mercurial