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 &params->prime) );
193 CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.subPrime,
194 &params->subPrime) );
195 CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.base, &params->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, &params->subPrime, &seed);
289 if (rv == SECSuccess) {
290 if (seed.len != PQG_GetLength(&params->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(&params->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 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)