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 }