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