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 |