Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/freebl/dsa.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
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 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 } |