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
fips186Change_ReduceModQForDSA(const PRUint8 * w,const PRUint8 * q,unsigned int qLen,PRUint8 * xj)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
FIPS186Change_ReduceModQForDSA(const unsigned char * w,const unsigned char * q,unsigned char * xj)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
FIPS186Change_GenerateX(PRUint8 * XKEY,const PRUint8 * XSEEDj,PRUint8 * x_j)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
dsa_GenerateGlobalRandomBytes(const SECItem * qItem,PRUint8 * dest,unsigned int * destLen,unsigned int maxDestLen)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
translate_mpi_error(mp_err err)148 translate_mpi_error(mp_err err)
149 {
150 MP_TO_SEC_ERROR(err);
151 }
152
153 static SECStatus
dsa_NewKeyExtended(const PQGParams * params,const SECItem * seed,DSAPrivateKey ** privKey)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
DSA_NewRandom(PLArenaPool * arena,const SECItem * q,SECItem * seed)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
DSA_NewKey(const PQGParams * params,DSAPrivateKey ** privKey)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
DSA_NewKeyFromSeed(const PQGParams * params,const unsigned char * seed,DSAPrivateKey ** privKey)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
dsa_SignDigest(DSAPrivateKey * key,SECItem * signature,const SECItem * digest,const unsigned char * kbytes)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_Memset(localDigestData, 0, 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
DSA_SignDigest(DSAPrivateKey * key,SECItem * signature,const SECItem * digest)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_Memset(kSeed, 0, sizeof kSeed);
536 return rv;
537 }
538
539 /* For FIPS compliance testing. Seed must be exactly 20 bytes. */
540 SECStatus
DSA_SignDigestWithSeed(DSAPrivateKey * key,SECItem * signature,const SECItem * digest,const unsigned char * seed)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
DSA_VerifyDigest(DSAPublicKey * key,const SECItem * signature,const SECItem * digest)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_Memset(localDigestData, 0, 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 }
692