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