1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/dsa.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,631 @@ 1.4 +/* 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifdef FREEBL_NO_DEPEND 1.11 +#include "stubs.h" 1.12 +#endif 1.13 + 1.14 +#include "prerror.h" 1.15 +#include "secerr.h" 1.16 + 1.17 +#include "prtypes.h" 1.18 +#include "prinit.h" 1.19 +#include "blapi.h" 1.20 +#include "nssilock.h" 1.21 +#include "secitem.h" 1.22 +#include "blapi.h" 1.23 +#include "mpi.h" 1.24 +#include "secmpi.h" 1.25 +#include "pqg.h" 1.26 + 1.27 + /* XXX to be replaced by define in blapit.h */ 1.28 +#define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048 1.29 + 1.30 +/* 1.31 + * FIPS 186-2 requires result from random output to be reduced mod q when 1.32 + * generating random numbers for DSA. 1.33 + * 1.34 + * Input: w, 2*qLen bytes 1.35 + * q, qLen bytes 1.36 + * Output: xj, qLen bytes 1.37 + */ 1.38 +static SECStatus 1.39 +fips186Change_ReduceModQForDSA(const PRUint8 *w, const PRUint8 *q, 1.40 + unsigned int qLen, PRUint8 * xj) 1.41 +{ 1.42 + mp_int W, Q, Xj; 1.43 + mp_err err; 1.44 + SECStatus rv = SECSuccess; 1.45 + 1.46 + /* Initialize MPI integers. */ 1.47 + MP_DIGITS(&W) = 0; 1.48 + MP_DIGITS(&Q) = 0; 1.49 + MP_DIGITS(&Xj) = 0; 1.50 + CHECK_MPI_OK( mp_init(&W) ); 1.51 + CHECK_MPI_OK( mp_init(&Q) ); 1.52 + CHECK_MPI_OK( mp_init(&Xj) ); 1.53 + /* 1.54 + * Convert input arguments into MPI integers. 1.55 + */ 1.56 + CHECK_MPI_OK( mp_read_unsigned_octets(&W, w, 2*qLen) ); 1.57 + CHECK_MPI_OK( mp_read_unsigned_octets(&Q, q, qLen) ); 1.58 + 1.59 + /* 1.60 + * Algorithm 1 of FIPS 186-2 Change Notice 1, Step 3.3 1.61 + * 1.62 + * xj = (w0 || w1) mod q 1.63 + */ 1.64 + CHECK_MPI_OK( mp_mod(&W, &Q, &Xj) ); 1.65 + CHECK_MPI_OK( mp_to_fixlen_octets(&Xj, xj, qLen) ); 1.66 +cleanup: 1.67 + mp_clear(&W); 1.68 + mp_clear(&Q); 1.69 + mp_clear(&Xj); 1.70 + if (err) { 1.71 + MP_TO_SEC_ERROR(err); 1.72 + rv = SECFailure; 1.73 + } 1.74 + return rv; 1.75 +} 1.76 + 1.77 +/* 1.78 + * FIPS 186-2 requires result from random output to be reduced mod q when 1.79 + * generating random numbers for DSA. 1.80 + */ 1.81 +SECStatus 1.82 +FIPS186Change_ReduceModQForDSA(const unsigned char *w, 1.83 + const unsigned char *q, 1.84 + unsigned char *xj) { 1.85 + return fips186Change_ReduceModQForDSA(w, q, DSA1_SUBPRIME_LEN, xj); 1.86 +} 1.87 + 1.88 +/* 1.89 + * The core of Algorithm 1 of FIPS 186-2 Change Notice 1. 1.90 + * 1.91 + * We no longer support FIPS 186-2 RNG. This function was exported 1.92 + * for power-up self tests and FIPS tests. Keep this stub, which fails, 1.93 + * to prevent crashes, but also to signal to test code that FIPS 186-2 1.94 + * RNG is no longer supported. 1.95 + */ 1.96 +SECStatus 1.97 +FIPS186Change_GenerateX(PRUint8 *XKEY, const PRUint8 *XSEEDj, 1.98 + PRUint8 *x_j) 1.99 +{ 1.100 + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 1.101 + return SECFailure; 1.102 +} 1.103 + 1.104 +/* 1.105 + * Specialized RNG for DSA 1.106 + * 1.107 + * As per Algorithm 1 of FIPS 186-2 Change Notice 1, in step 3.3 the value 1.108 + * Xj should be reduced mod q, a 160-bit prime number. Since this parameter 1.109 + * is only meaningful in the context of DSA, the above RNG functions 1.110 + * were implemented without it. They are re-implemented below for use 1.111 + * with DSA. 1.112 + */ 1.113 + 1.114 +/* 1.115 +** Generate some random bytes, using the global random number generator 1.116 +** object. In DSA mode, so there is a q. 1.117 +*/ 1.118 +static SECStatus 1.119 +dsa_GenerateGlobalRandomBytes(const SECItem * qItem, PRUint8 * dest, 1.120 + unsigned int * destLen, unsigned int maxDestLen) 1.121 +{ 1.122 + SECStatus rv; 1.123 + SECItem w; 1.124 + const PRUint8 * q = qItem->data; 1.125 + unsigned int qLen = qItem->len; 1.126 + 1.127 + if (*q == 0) { 1.128 + ++q; 1.129 + --qLen; 1.130 + } 1.131 + if (maxDestLen < qLen) { 1.132 + /* This condition can occur when DSA_SignDigest is passed a group 1.133 + with a subprime that is larger than DSA_MAX_SUBPRIME_LEN. */ 1.134 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.135 + return SECFailure; 1.136 + } 1.137 + w.data = NULL; /* otherwise SECITEM_AllocItem asserts */ 1.138 + if (!SECITEM_AllocItem(NULL, &w, 2*qLen)) { 1.139 + return SECFailure; 1.140 + } 1.141 + *destLen = qLen; 1.142 + 1.143 + rv = RNG_GenerateGlobalRandomBytes(w.data, w.len); 1.144 + if (rv == SECSuccess) { 1.145 + rv = fips186Change_ReduceModQForDSA(w.data, q, qLen, dest); 1.146 + } 1.147 + 1.148 + SECITEM_FreeItem(&w, PR_FALSE); 1.149 + return rv; 1.150 +} 1.151 + 1.152 +static void translate_mpi_error(mp_err err) 1.153 +{ 1.154 + MP_TO_SEC_ERROR(err); 1.155 +} 1.156 + 1.157 +static SECStatus 1.158 +dsa_NewKeyExtended(const PQGParams *params, const SECItem * seed, 1.159 + DSAPrivateKey **privKey) 1.160 +{ 1.161 + mp_int p, g; 1.162 + mp_int x, y; 1.163 + mp_err err; 1.164 + PLArenaPool *arena; 1.165 + DSAPrivateKey *key; 1.166 + /* Check args. */ 1.167 + if (!params || !privKey || !seed || !seed->data) { 1.168 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.169 + return SECFailure; 1.170 + } 1.171 + /* Initialize an arena for the DSA key. */ 1.172 + arena = PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE); 1.173 + if (!arena) { 1.174 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.175 + return SECFailure; 1.176 + } 1.177 + key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey)); 1.178 + if (!key) { 1.179 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.180 + PORT_FreeArena(arena, PR_TRUE); 1.181 + return SECFailure; 1.182 + } 1.183 + key->params.arena = arena; 1.184 + /* Initialize MPI integers. */ 1.185 + MP_DIGITS(&p) = 0; 1.186 + MP_DIGITS(&g) = 0; 1.187 + MP_DIGITS(&x) = 0; 1.188 + MP_DIGITS(&y) = 0; 1.189 + CHECK_MPI_OK( mp_init(&p) ); 1.190 + CHECK_MPI_OK( mp_init(&g) ); 1.191 + CHECK_MPI_OK( mp_init(&x) ); 1.192 + CHECK_MPI_OK( mp_init(&y) ); 1.193 + /* Copy over the PQG params */ 1.194 + CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.prime, 1.195 + ¶ms->prime) ); 1.196 + CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.subPrime, 1.197 + ¶ms->subPrime) ); 1.198 + CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.base, ¶ms->base) ); 1.199 + /* Convert stored p, g, and received x into MPI integers. */ 1.200 + SECITEM_TO_MPINT(params->prime, &p); 1.201 + SECITEM_TO_MPINT(params->base, &g); 1.202 + OCTETS_TO_MPINT(seed->data, &x, seed->len); 1.203 + /* Store x in private key */ 1.204 + SECITEM_AllocItem(arena, &key->privateValue, seed->len); 1.205 + PORT_Memcpy(key->privateValue.data, seed->data, seed->len); 1.206 + /* Compute public key y = g**x mod p */ 1.207 + CHECK_MPI_OK( mp_exptmod(&g, &x, &p, &y) ); 1.208 + /* Store y in public key */ 1.209 + MPINT_TO_SECITEM(&y, &key->publicValue, arena); 1.210 + *privKey = key; 1.211 + key = NULL; 1.212 +cleanup: 1.213 + mp_clear(&p); 1.214 + mp_clear(&g); 1.215 + mp_clear(&x); 1.216 + mp_clear(&y); 1.217 + if (key) 1.218 + PORT_FreeArena(key->params.arena, PR_TRUE); 1.219 + if (err) { 1.220 + translate_mpi_error(err); 1.221 + return SECFailure; 1.222 + } 1.223 + return SECSuccess; 1.224 +} 1.225 + 1.226 +SECStatus 1.227 +DSA_NewRandom(PLArenaPool * arena, const SECItem * q, SECItem * seed) 1.228 +{ 1.229 + int retries = 10; 1.230 + unsigned int i; 1.231 + PRBool good; 1.232 + 1.233 + if (q == NULL || q->data == NULL || q->len == 0 || 1.234 + (q->data[0] == 0 && q->len == 1)) { 1.235 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.236 + return SECFailure; 1.237 + } 1.238 + 1.239 + if (!SECITEM_AllocItem(arena, seed, q->len)) { 1.240 + return SECFailure; 1.241 + } 1.242 + 1.243 + do { 1.244 + /* Generate seed bytes for x according to FIPS 186-1 appendix 3 */ 1.245 + if (dsa_GenerateGlobalRandomBytes(q, seed->data, &seed->len, 1.246 + seed->len)) { 1.247 + goto loser; 1.248 + } 1.249 + /* Disallow values of 0 and 1 for x. */ 1.250 + good = PR_FALSE; 1.251 + for (i = 0; i < seed->len-1; i++) { 1.252 + if (seed->data[i] != 0) { 1.253 + good = PR_TRUE; 1.254 + break; 1.255 + } 1.256 + } 1.257 + if (!good && seed->data[i] > 1) { 1.258 + good = PR_TRUE; 1.259 + } 1.260 + } while (!good && --retries > 0); 1.261 + 1.262 + if (!good) { 1.263 + PORT_SetError(SEC_ERROR_NEED_RANDOM); 1.264 +loser: if (arena != NULL) { 1.265 + SECITEM_FreeItem(seed, PR_FALSE); 1.266 + } 1.267 + return SECFailure; 1.268 + } 1.269 + 1.270 + return SECSuccess; 1.271 +} 1.272 + 1.273 +/* 1.274 +** Generate and return a new DSA public and private key pair, 1.275 +** both of which are encoded into a single DSAPrivateKey struct. 1.276 +** "params" is a pointer to the PQG parameters for the domain 1.277 +** Uses a random seed. 1.278 +*/ 1.279 +SECStatus 1.280 +DSA_NewKey(const PQGParams *params, DSAPrivateKey **privKey) 1.281 +{ 1.282 + SECItem seed; 1.283 + SECStatus rv; 1.284 + 1.285 + rv = PQG_Check(params); 1.286 + if (rv != SECSuccess) { 1.287 + return rv; 1.288 + } 1.289 + seed.data = NULL; 1.290 + 1.291 + rv = DSA_NewRandom(NULL, ¶ms->subPrime, &seed); 1.292 + if (rv == SECSuccess) { 1.293 + if (seed.len != PQG_GetLength(¶ms->subPrime)) { 1.294 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.295 + rv = SECFailure; 1.296 + } else { 1.297 + rv = dsa_NewKeyExtended(params, &seed, privKey); 1.298 + } 1.299 + } 1.300 + SECITEM_FreeItem(&seed, PR_FALSE); 1.301 + return rv; 1.302 +} 1.303 + 1.304 +/* For FIPS compliance testing. Seed must be exactly the size of subPrime */ 1.305 +SECStatus 1.306 +DSA_NewKeyFromSeed(const PQGParams *params, 1.307 + const unsigned char *seed, 1.308 + DSAPrivateKey **privKey) 1.309 +{ 1.310 + SECItem seedItem; 1.311 + seedItem.data = (unsigned char*) seed; 1.312 + seedItem.len = PQG_GetLength(¶ms->subPrime); 1.313 + return dsa_NewKeyExtended(params, &seedItem, privKey); 1.314 +} 1.315 + 1.316 +static SECStatus 1.317 +dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest, 1.318 + const unsigned char *kb) 1.319 +{ 1.320 + mp_int p, q, g; /* PQG parameters */ 1.321 + mp_int x, k; /* private key & pseudo-random integer */ 1.322 + mp_int r, s; /* tuple (r, s) is signature) */ 1.323 + mp_err err = MP_OKAY; 1.324 + SECStatus rv = SECSuccess; 1.325 + unsigned int dsa_subprime_len, dsa_signature_len, offset; 1.326 + SECItem localDigest; 1.327 + unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN]; 1.328 + 1.329 + 1.330 + /* FIPS-compliance dictates that digest is a SHA hash. */ 1.331 + /* Check args. */ 1.332 + if (!key || !signature || !digest) { 1.333 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.334 + return SECFailure; 1.335 + } 1.336 + 1.337 + dsa_subprime_len = PQG_GetLength(&key->params.subPrime); 1.338 + dsa_signature_len = dsa_subprime_len*2; 1.339 + if ((signature->len < dsa_signature_len) || 1.340 + (digest->len > HASH_LENGTH_MAX) || 1.341 + (digest->len < SHA1_LENGTH)) { 1.342 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.343 + return SECFailure; 1.344 + } 1.345 + 1.346 + /* DSA accepts digests not equal to dsa_subprime_len, if the 1.347 + * digests are greater, then they are truncated to the size of 1.348 + * dsa_subprime_len, using the left most bits. If they are less 1.349 + * then they are padded on the left.*/ 1.350 + PORT_Memset(localDigestData, 0, dsa_subprime_len); 1.351 + offset = (digest->len < dsa_subprime_len) ? 1.352 + (dsa_subprime_len - digest->len) : 0; 1.353 + PORT_Memcpy(localDigestData+offset, digest->data, 1.354 + dsa_subprime_len - offset); 1.355 + localDigest.data = localDigestData; 1.356 + localDigest.len = dsa_subprime_len; 1.357 + 1.358 + /* Initialize MPI integers. */ 1.359 + MP_DIGITS(&p) = 0; 1.360 + MP_DIGITS(&q) = 0; 1.361 + MP_DIGITS(&g) = 0; 1.362 + MP_DIGITS(&x) = 0; 1.363 + MP_DIGITS(&k) = 0; 1.364 + MP_DIGITS(&r) = 0; 1.365 + MP_DIGITS(&s) = 0; 1.366 + CHECK_MPI_OK( mp_init(&p) ); 1.367 + CHECK_MPI_OK( mp_init(&q) ); 1.368 + CHECK_MPI_OK( mp_init(&g) ); 1.369 + CHECK_MPI_OK( mp_init(&x) ); 1.370 + CHECK_MPI_OK( mp_init(&k) ); 1.371 + CHECK_MPI_OK( mp_init(&r) ); 1.372 + CHECK_MPI_OK( mp_init(&s) ); 1.373 + /* 1.374 + ** Convert stored PQG and private key into MPI integers. 1.375 + */ 1.376 + SECITEM_TO_MPINT(key->params.prime, &p); 1.377 + SECITEM_TO_MPINT(key->params.subPrime, &q); 1.378 + SECITEM_TO_MPINT(key->params.base, &g); 1.379 + SECITEM_TO_MPINT(key->privateValue, &x); 1.380 + OCTETS_TO_MPINT(kb, &k, dsa_subprime_len); 1.381 + /* 1.382 + ** FIPS 186-1, Section 5, Step 1 1.383 + ** 1.384 + ** r = (g**k mod p) mod q 1.385 + */ 1.386 + CHECK_MPI_OK( mp_exptmod(&g, &k, &p, &r) ); /* r = g**k mod p */ 1.387 + CHECK_MPI_OK( mp_mod(&r, &q, &r) ); /* r = r mod q */ 1.388 + /* 1.389 + ** FIPS 186-1, Section 5, Step 2 1.390 + ** 1.391 + ** s = (k**-1 * (HASH(M) + x*r)) mod q 1.392 + */ 1.393 + SECITEM_TO_MPINT(localDigest, &s); /* s = HASH(M) */ 1.394 + CHECK_MPI_OK( mp_invmod(&k, &q, &k) ); /* k = k**-1 mod q */ 1.395 + CHECK_MPI_OK( mp_mulmod(&x, &r, &q, &x) ); /* x = x * r mod q */ 1.396 + CHECK_MPI_OK( mp_addmod(&s, &x, &q, &s) ); /* s = s + x mod q */ 1.397 + CHECK_MPI_OK( mp_mulmod(&s, &k, &q, &s) ); /* s = s * k mod q */ 1.398 + /* 1.399 + ** verify r != 0 and s != 0 1.400 + ** mentioned as optional in FIPS 186-1. 1.401 + */ 1.402 + if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) { 1.403 + PORT_SetError(SEC_ERROR_NEED_RANDOM); 1.404 + rv = SECFailure; 1.405 + goto cleanup; 1.406 + } 1.407 + /* 1.408 + ** Step 4 1.409 + ** 1.410 + ** Signature is tuple (r, s) 1.411 + */ 1.412 + err = mp_to_fixlen_octets(&r, signature->data, dsa_subprime_len); 1.413 + if (err < 0) goto cleanup; 1.414 + err = mp_to_fixlen_octets(&s, signature->data + dsa_subprime_len, 1.415 + dsa_subprime_len); 1.416 + if (err < 0) goto cleanup; 1.417 + err = MP_OKAY; 1.418 + signature->len = dsa_signature_len; 1.419 +cleanup: 1.420 + PORT_Memset(localDigestData, 0, DSA_MAX_SUBPRIME_LEN); 1.421 + mp_clear(&p); 1.422 + mp_clear(&q); 1.423 + mp_clear(&g); 1.424 + mp_clear(&x); 1.425 + mp_clear(&k); 1.426 + mp_clear(&r); 1.427 + mp_clear(&s); 1.428 + if (err) { 1.429 + translate_mpi_error(err); 1.430 + rv = SECFailure; 1.431 + } 1.432 + return rv; 1.433 +} 1.434 + 1.435 +/* signature is caller-supplied buffer of at least 40 bytes. 1.436 +** On input, signature->len == size of buffer to hold signature. 1.437 +** digest->len == size of digest. 1.438 +** On output, signature->len == size of signature in buffer. 1.439 +** Uses a random seed. 1.440 +*/ 1.441 +SECStatus 1.442 +DSA_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest) 1.443 +{ 1.444 + SECStatus rv; 1.445 + int retries = 10; 1.446 + unsigned char kSeed[DSA_MAX_SUBPRIME_LEN]; 1.447 + unsigned int kSeedLen = 0; 1.448 + unsigned int i; 1.449 + unsigned int dsa_subprime_len = PQG_GetLength(&key->params.subPrime); 1.450 + PRBool good; 1.451 + 1.452 + PORT_SetError(0); 1.453 + do { 1.454 + rv = dsa_GenerateGlobalRandomBytes(&key->params.subPrime, 1.455 + kSeed, &kSeedLen, sizeof kSeed); 1.456 + if (rv != SECSuccess) 1.457 + break; 1.458 + if (kSeedLen != dsa_subprime_len) { 1.459 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.460 + rv = SECFailure; 1.461 + break; 1.462 + } 1.463 + /* Disallow a value of 0 for k. */ 1.464 + good = PR_FALSE; 1.465 + for (i = 0; i < kSeedLen; i++) { 1.466 + if (kSeed[i] != 0) { 1.467 + good = PR_TRUE; 1.468 + break; 1.469 + } 1.470 + } 1.471 + if (!good) { 1.472 + PORT_SetError(SEC_ERROR_NEED_RANDOM); 1.473 + rv = SECFailure; 1.474 + continue; 1.475 + } 1.476 + rv = dsa_SignDigest(key, signature, digest, kSeed); 1.477 + } while (rv != SECSuccess && PORT_GetError() == SEC_ERROR_NEED_RANDOM && 1.478 + --retries > 0); 1.479 + return rv; 1.480 +} 1.481 + 1.482 +/* For FIPS compliance testing. Seed must be exactly 20 bytes. */ 1.483 +SECStatus 1.484 +DSA_SignDigestWithSeed(DSAPrivateKey * key, 1.485 + SECItem * signature, 1.486 + const SECItem * digest, 1.487 + const unsigned char * seed) 1.488 +{ 1.489 + SECStatus rv; 1.490 + rv = dsa_SignDigest(key, signature, digest, seed); 1.491 + return rv; 1.492 +} 1.493 + 1.494 +/* signature is caller-supplied buffer of at least 20 bytes. 1.495 +** On input, signature->len == size of buffer to hold signature. 1.496 +** digest->len == size of digest. 1.497 +*/ 1.498 +SECStatus 1.499 +DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature, 1.500 + const SECItem *digest) 1.501 +{ 1.502 + /* FIPS-compliance dictates that digest is a SHA hash. */ 1.503 + mp_int p, q, g; /* PQG parameters */ 1.504 + mp_int r_, s_; /* tuple (r', s') is received signature) */ 1.505 + mp_int u1, u2, v, w; /* intermediate values used in verification */ 1.506 + mp_int y; /* public key */ 1.507 + mp_err err; 1.508 + int dsa_subprime_len, dsa_signature_len, offset; 1.509 + SECItem localDigest; 1.510 + unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN]; 1.511 + SECStatus verified = SECFailure; 1.512 + 1.513 + /* Check args. */ 1.514 + if (!key || !signature || !digest ) { 1.515 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.516 + return SECFailure; 1.517 + } 1.518 + 1.519 + dsa_subprime_len = PQG_GetLength(&key->params.subPrime); 1.520 + dsa_signature_len = dsa_subprime_len*2; 1.521 + if ((signature->len != dsa_signature_len) || 1.522 + (digest->len > HASH_LENGTH_MAX) || 1.523 + (digest->len < SHA1_LENGTH)) { 1.524 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.525 + return SECFailure; 1.526 + } 1.527 + 1.528 + /* DSA accepts digests not equal to dsa_subprime_len, if the 1.529 + * digests are greater, than they are truncated to the size of 1.530 + * dsa_subprime_len, using the left most bits. If they are less 1.531 + * then they are padded on the left.*/ 1.532 + PORT_Memset(localDigestData, 0, dsa_subprime_len); 1.533 + offset = (digest->len < dsa_subprime_len) ? 1.534 + (dsa_subprime_len - digest->len) : 0; 1.535 + PORT_Memcpy(localDigestData+offset, digest->data, 1.536 + dsa_subprime_len - offset); 1.537 + localDigest.data = localDigestData; 1.538 + localDigest.len = dsa_subprime_len; 1.539 + 1.540 + /* Initialize MPI integers. */ 1.541 + MP_DIGITS(&p) = 0; 1.542 + MP_DIGITS(&q) = 0; 1.543 + MP_DIGITS(&g) = 0; 1.544 + MP_DIGITS(&y) = 0; 1.545 + MP_DIGITS(&r_) = 0; 1.546 + MP_DIGITS(&s_) = 0; 1.547 + MP_DIGITS(&u1) = 0; 1.548 + MP_DIGITS(&u2) = 0; 1.549 + MP_DIGITS(&v) = 0; 1.550 + MP_DIGITS(&w) = 0; 1.551 + CHECK_MPI_OK( mp_init(&p) ); 1.552 + CHECK_MPI_OK( mp_init(&q) ); 1.553 + CHECK_MPI_OK( mp_init(&g) ); 1.554 + CHECK_MPI_OK( mp_init(&y) ); 1.555 + CHECK_MPI_OK( mp_init(&r_) ); 1.556 + CHECK_MPI_OK( mp_init(&s_) ); 1.557 + CHECK_MPI_OK( mp_init(&u1) ); 1.558 + CHECK_MPI_OK( mp_init(&u2) ); 1.559 + CHECK_MPI_OK( mp_init(&v) ); 1.560 + CHECK_MPI_OK( mp_init(&w) ); 1.561 + /* 1.562 + ** Convert stored PQG and public key into MPI integers. 1.563 + */ 1.564 + SECITEM_TO_MPINT(key->params.prime, &p); 1.565 + SECITEM_TO_MPINT(key->params.subPrime, &q); 1.566 + SECITEM_TO_MPINT(key->params.base, &g); 1.567 + SECITEM_TO_MPINT(key->publicValue, &y); 1.568 + /* 1.569 + ** Convert received signature (r', s') into MPI integers. 1.570 + */ 1.571 + OCTETS_TO_MPINT(signature->data, &r_, dsa_subprime_len); 1.572 + OCTETS_TO_MPINT(signature->data + dsa_subprime_len, &s_, dsa_subprime_len); 1.573 + /* 1.574 + ** Verify that 0 < r' < q and 0 < s' < q 1.575 + */ 1.576 + if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 || 1.577 + mp_cmp(&r_, &q) >= 0 || mp_cmp(&s_, &q) >= 0) { 1.578 + /* err is zero here. */ 1.579 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.580 + goto cleanup; /* will return verified == SECFailure */ 1.581 + } 1.582 + /* 1.583 + ** FIPS 186-1, Section 6, Step 1 1.584 + ** 1.585 + ** w = (s')**-1 mod q 1.586 + */ 1.587 + CHECK_MPI_OK( mp_invmod(&s_, &q, &w) ); /* w = (s')**-1 mod q */ 1.588 + /* 1.589 + ** FIPS 186-1, Section 6, Step 2 1.590 + ** 1.591 + ** u1 = ((Hash(M')) * w) mod q 1.592 + */ 1.593 + SECITEM_TO_MPINT(localDigest, &u1); /* u1 = HASH(M') */ 1.594 + CHECK_MPI_OK( mp_mulmod(&u1, &w, &q, &u1) ); /* u1 = u1 * w mod q */ 1.595 + /* 1.596 + ** FIPS 186-1, Section 6, Step 3 1.597 + ** 1.598 + ** u2 = ((r') * w) mod q 1.599 + */ 1.600 + CHECK_MPI_OK( mp_mulmod(&r_, &w, &q, &u2) ); 1.601 + /* 1.602 + ** FIPS 186-1, Section 6, Step 4 1.603 + ** 1.604 + ** v = ((g**u1 * y**u2) mod p) mod q 1.605 + */ 1.606 + CHECK_MPI_OK( mp_exptmod(&g, &u1, &p, &g) ); /* g = g**u1 mod p */ 1.607 + CHECK_MPI_OK( mp_exptmod(&y, &u2, &p, &y) ); /* y = y**u2 mod p */ 1.608 + CHECK_MPI_OK( mp_mulmod(&g, &y, &p, &v) ); /* v = g * y mod p */ 1.609 + CHECK_MPI_OK( mp_mod(&v, &q, &v) ); /* v = v mod q */ 1.610 + /* 1.611 + ** Verification: v == r' 1.612 + */ 1.613 + if (mp_cmp(&v, &r_)) { 1.614 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.615 + verified = SECFailure; /* Signature failed to verify. */ 1.616 + } else { 1.617 + verified = SECSuccess; /* Signature verified. */ 1.618 + } 1.619 +cleanup: 1.620 + mp_clear(&p); 1.621 + mp_clear(&q); 1.622 + mp_clear(&g); 1.623 + mp_clear(&y); 1.624 + mp_clear(&r_); 1.625 + mp_clear(&s_); 1.626 + mp_clear(&u1); 1.627 + mp_clear(&u2); 1.628 + mp_clear(&v); 1.629 + mp_clear(&w); 1.630 + if (err) { 1.631 + translate_mpi_error(err); 1.632 + } 1.633 + return verified; 1.634 +}