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 ¶ms->prime)); 192 CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.subPrime, 193 ¶ms->subPrime)); 194 CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.base, ¶ms->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, ¶ms->subPrime, &seed); 290 if (rv == SECSuccess) { 291 if (seed.len != PQG_GetLength(¶ms->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(¶ms->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 }