/security/nss/lib/freebl/dsa.c

http://github.com/zpao/v8monkey · C · 612 lines · 404 code · 34 blank · 174 comment · 75 complexity · c5f7ed323f4221201c1be27a5932833e MD5 · raw file

  1. /*
  2. *
  3. * ***** BEGIN LICENSE BLOCK *****
  4. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  5. *
  6. * The contents of this file are subject to the Mozilla Public License Version
  7. * 1.1 (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. * http://www.mozilla.org/MPL/
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. *
  16. * The Original Code is the Netscape security libraries.
  17. *
  18. * The Initial Developer of the Original Code is
  19. * Netscape Communications Corporation.
  20. * Portions created by the Initial Developer are Copyright (C) 1994-2000
  21. * the Initial Developer. All Rights Reserved.
  22. *
  23. * Contributor(s):
  24. *
  25. * Alternatively, the contents of this file may be used under the terms of
  26. * either the GNU General Public License Version 2 or later (the "GPL"), or
  27. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28. * in which case the provisions of the GPL or the LGPL are applicable instead
  29. * of those above. If you wish to allow use of your version of this file only
  30. * under the terms of either the GPL or the LGPL, and not to allow others to
  31. * use your version of this file under the terms of the MPL, indicate your
  32. * decision by deleting the provisions above and replace them with the notice
  33. * and other provisions required by the GPL or the LGPL. If you do not delete
  34. * the provisions above, a recipient may use your version of this file under
  35. * the terms of any one of the MPL, the GPL or the LGPL.
  36. *
  37. * ***** END LICENSE BLOCK ***** */
  38. /* $Id: dsa.c,v 1.21 2010/12/04 18:57:16 rrelyea%redhat.com Exp $ */
  39. #ifdef FREEBL_NO_DEPEND
  40. #include "stubs.h"
  41. #endif
  42. #include "prerror.h"
  43. #include "secerr.h"
  44. #include "prtypes.h"
  45. #include "prinit.h"
  46. #include "blapi.h"
  47. #include "nssilock.h"
  48. #include "secitem.h"
  49. #include "blapi.h"
  50. #include "mpi.h"
  51. #include "secmpi.h"
  52. /* XXX to be replaced by define in blapit.h */
  53. #define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048
  54. /*
  55. * FIPS 186-2 requires result from random output to be reduced mod q when
  56. * generating random numbers for DSA.
  57. *
  58. * Input: w, 2*qLen bytes
  59. * q, qLen bytes
  60. * Output: xj, qLen bytes
  61. */
  62. static SECStatus
  63. fips186Change_ReduceModQForDSA(const PRUint8 *w, const PRUint8 *q,
  64. unsigned int qLen, PRUint8 * xj)
  65. {
  66. mp_int W, Q, Xj;
  67. mp_err err;
  68. SECStatus rv = SECSuccess;
  69. /* Initialize MPI integers. */
  70. MP_DIGITS(&W) = 0;
  71. MP_DIGITS(&Q) = 0;
  72. MP_DIGITS(&Xj) = 0;
  73. CHECK_MPI_OK( mp_init(&W) );
  74. CHECK_MPI_OK( mp_init(&Q) );
  75. CHECK_MPI_OK( mp_init(&Xj) );
  76. /*
  77. * Convert input arguments into MPI integers.
  78. */
  79. CHECK_MPI_OK( mp_read_unsigned_octets(&W, w, 2*qLen) );
  80. CHECK_MPI_OK( mp_read_unsigned_octets(&Q, q, qLen) );
  81. /*
  82. * Algorithm 1 of FIPS 186-2 Change Notice 1, Step 3.3
  83. *
  84. * xj = (w0 || w1) mod q
  85. */
  86. CHECK_MPI_OK( mp_mod(&W, &Q, &Xj) );
  87. CHECK_MPI_OK( mp_to_fixlen_octets(&Xj, xj, qLen) );
  88. cleanup:
  89. mp_clear(&W);
  90. mp_clear(&Q);
  91. mp_clear(&Xj);
  92. if (err) {
  93. MP_TO_SEC_ERROR(err);
  94. rv = SECFailure;
  95. }
  96. return rv;
  97. }
  98. /*
  99. * FIPS 186-2 requires result from random output to be reduced mod q when
  100. * generating random numbers for DSA.
  101. */
  102. SECStatus
  103. FIPS186Change_ReduceModQForDSA(const unsigned char *w,
  104. const unsigned char *q,
  105. unsigned char *xj) {
  106. return fips186Change_ReduceModQForDSA(w, q, DSA_SUBPRIME_LEN, xj);
  107. }
  108. /*
  109. * The core of Algorithm 1 of FIPS 186-2 Change Notice 1.
  110. *
  111. * We no longer support FIPS 186-2 RNG. This function was exported
  112. * for power-up self tests and FIPS tests. Keep this stub, which fails,
  113. * to prevent crashes, but also to signal to test code that FIPS 186-2
  114. * RNG is no longer supported.
  115. */
  116. SECStatus
  117. FIPS186Change_GenerateX(PRUint8 *XKEY, const PRUint8 *XSEEDj,
  118. PRUint8 *x_j)
  119. {
  120. PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
  121. return SECFailure;
  122. }
  123. /*
  124. * Specialized RNG for DSA
  125. *
  126. * As per Algorithm 1 of FIPS 186-2 Change Notice 1, in step 3.3 the value
  127. * Xj should be reduced mod q, a 160-bit prime number. Since this parameter
  128. * is only meaningful in the context of DSA, the above RNG functions
  129. * were implemented without it. They are re-implemented below for use
  130. * with DSA.
  131. */
  132. /*
  133. ** Generate some random bytes, using the global random number generator
  134. ** object. In DSA mode, so there is a q.
  135. */
  136. static SECStatus
  137. dsa_GenerateGlobalRandomBytes(const SECItem * qItem, PRUint8 * dest,
  138. unsigned int * destLen, unsigned int maxDestLen)
  139. {
  140. SECStatus rv;
  141. SECItem w;
  142. const PRUint8 * q = qItem->data;
  143. unsigned int qLen = qItem->len;
  144. if (*q == 0) {
  145. ++q;
  146. --qLen;
  147. }
  148. if (maxDestLen < qLen) {
  149. /* This condition can occur when DSA_SignDigest is passed a group
  150. with a subprime that is larger than DSA_SUBPRIME_LEN. */
  151. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  152. return SECFailure;
  153. }
  154. w.data = NULL; /* otherwise SECITEM_AllocItem asserts */
  155. if (!SECITEM_AllocItem(NULL, &w, 2*qLen)) {
  156. return SECFailure;
  157. }
  158. *destLen = qLen;
  159. rv = RNG_GenerateGlobalRandomBytes(w.data, w.len);
  160. if (rv == SECSuccess) {
  161. rv = fips186Change_ReduceModQForDSA(w.data, q, qLen, dest);
  162. }
  163. SECITEM_FreeItem(&w, PR_FALSE);
  164. return rv;
  165. }
  166. static void translate_mpi_error(mp_err err)
  167. {
  168. MP_TO_SEC_ERROR(err);
  169. }
  170. static SECStatus
  171. dsa_NewKeyExtended(const PQGParams *params, const SECItem * seed,
  172. DSAPrivateKey **privKey)
  173. {
  174. mp_int p, g;
  175. mp_int x, y;
  176. mp_err err;
  177. PRArenaPool *arena;
  178. DSAPrivateKey *key;
  179. /* Check args. */
  180. if (!params || !privKey || !seed || !seed->data) {
  181. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  182. return SECFailure;
  183. }
  184. /* Initialize an arena for the DSA key. */
  185. arena = PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE);
  186. if (!arena) {
  187. PORT_SetError(SEC_ERROR_NO_MEMORY);
  188. return SECFailure;
  189. }
  190. key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
  191. if (!key) {
  192. PORT_SetError(SEC_ERROR_NO_MEMORY);
  193. PORT_FreeArena(arena, PR_TRUE);
  194. return SECFailure;
  195. }
  196. key->params.arena = arena;
  197. /* Initialize MPI integers. */
  198. MP_DIGITS(&p) = 0;
  199. MP_DIGITS(&g) = 0;
  200. MP_DIGITS(&x) = 0;
  201. MP_DIGITS(&y) = 0;
  202. CHECK_MPI_OK( mp_init(&p) );
  203. CHECK_MPI_OK( mp_init(&g) );
  204. CHECK_MPI_OK( mp_init(&x) );
  205. CHECK_MPI_OK( mp_init(&y) );
  206. /* Copy over the PQG params */
  207. CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.prime,
  208. &params->prime) );
  209. CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.subPrime,
  210. &params->subPrime) );
  211. CHECK_MPI_OK( SECITEM_CopyItem(arena, &key->params.base, &params->base) );
  212. /* Convert stored p, g, and received x into MPI integers. */
  213. SECITEM_TO_MPINT(params->prime, &p);
  214. SECITEM_TO_MPINT(params->base, &g);
  215. OCTETS_TO_MPINT(seed->data, &x, seed->len);
  216. /* Store x in private key */
  217. SECITEM_AllocItem(arena, &key->privateValue, seed->len);
  218. PORT_Memcpy(key->privateValue.data, seed->data, seed->len);
  219. /* Compute public key y = g**x mod p */
  220. CHECK_MPI_OK( mp_exptmod(&g, &x, &p, &y) );
  221. /* Store y in public key */
  222. MPINT_TO_SECITEM(&y, &key->publicValue, arena);
  223. *privKey = key;
  224. key = NULL;
  225. cleanup:
  226. mp_clear(&p);
  227. mp_clear(&g);
  228. mp_clear(&x);
  229. mp_clear(&y);
  230. if (key)
  231. PORT_FreeArena(key->params.arena, PR_TRUE);
  232. if (err) {
  233. translate_mpi_error(err);
  234. return SECFailure;
  235. }
  236. return SECSuccess;
  237. }
  238. SECStatus
  239. DSA_NewRandom(PLArenaPool * arena, const SECItem * q, SECItem * seed)
  240. {
  241. int retries = 10;
  242. unsigned int i;
  243. PRBool good;
  244. if (q == NULL || q->data == NULL || q->len == 0 ||
  245. (q->data[0] == 0 && q->len == 1)) {
  246. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  247. return SECFailure;
  248. }
  249. if (!SECITEM_AllocItem(arena, seed, q->len)) {
  250. return SECFailure;
  251. }
  252. do {
  253. /* Generate seed bytes for x according to FIPS 186-1 appendix 3 */
  254. if (dsa_GenerateGlobalRandomBytes(q, seed->data, &seed->len,
  255. seed->len)) {
  256. goto loser;
  257. }
  258. /* Disallow values of 0 and 1 for x. */
  259. good = PR_FALSE;
  260. for (i = 0; i < seed->len-1; i++) {
  261. if (seed->data[i] != 0) {
  262. good = PR_TRUE;
  263. break;
  264. }
  265. }
  266. if (!good && seed->data[i] > 1) {
  267. good = PR_TRUE;
  268. }
  269. } while (!good && --retries > 0);
  270. if (!good) {
  271. PORT_SetError(SEC_ERROR_NEED_RANDOM);
  272. loser: if (arena != NULL) {
  273. SECITEM_FreeItem(seed, PR_FALSE);
  274. }
  275. return SECFailure;
  276. }
  277. return SECSuccess;
  278. }
  279. /*
  280. ** Generate and return a new DSA public and private key pair,
  281. ** both of which are encoded into a single DSAPrivateKey struct.
  282. ** "params" is a pointer to the PQG parameters for the domain
  283. ** Uses a random seed.
  284. */
  285. SECStatus
  286. DSA_NewKey(const PQGParams *params, DSAPrivateKey **privKey)
  287. {
  288. SECItem seed;
  289. SECStatus rv;
  290. seed.data = NULL;
  291. rv = DSA_NewRandom(NULL, &params->subPrime, &seed);
  292. if (rv == SECSuccess) {
  293. if (seed.len != DSA_SUBPRIME_LEN) {
  294. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  295. rv = SECFailure;
  296. } else {
  297. rv = dsa_NewKeyExtended(params, &seed, privKey);
  298. }
  299. }
  300. SECITEM_FreeItem(&seed, PR_FALSE);
  301. return rv;
  302. }
  303. /* For FIPS compliance testing. Seed must be exactly 20 bytes long */
  304. SECStatus
  305. DSA_NewKeyFromSeed(const PQGParams *params,
  306. const unsigned char *seed,
  307. DSAPrivateKey **privKey)
  308. {
  309. /* TODO: check Q size */
  310. SECItem seedItem;
  311. seedItem.data = (unsigned char*) seed;
  312. seedItem.len = DSA_SUBPRIME_LEN;
  313. return dsa_NewKeyExtended(params, &seedItem, privKey);
  314. }
  315. static SECStatus
  316. dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
  317. const unsigned char *kb)
  318. {
  319. mp_int p, q, g; /* PQG parameters */
  320. mp_int x, k; /* private key & pseudo-random integer */
  321. mp_int r, s; /* tuple (r, s) is signature) */
  322. mp_err err = MP_OKAY;
  323. SECStatus rv = SECSuccess;
  324. /* FIPS-compliance dictates that digest is a SHA1 hash. */
  325. /* Check args. */
  326. if (!key || !signature || !digest ||
  327. (signature->len < DSA_SIGNATURE_LEN) ||
  328. (digest->len != SHA1_LENGTH)) {
  329. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  330. return SECFailure;
  331. }
  332. /* Initialize MPI integers. */
  333. MP_DIGITS(&p) = 0;
  334. MP_DIGITS(&q) = 0;
  335. MP_DIGITS(&g) = 0;
  336. MP_DIGITS(&x) = 0;
  337. MP_DIGITS(&k) = 0;
  338. MP_DIGITS(&r) = 0;
  339. MP_DIGITS(&s) = 0;
  340. CHECK_MPI_OK( mp_init(&p) );
  341. CHECK_MPI_OK( mp_init(&q) );
  342. CHECK_MPI_OK( mp_init(&g) );
  343. CHECK_MPI_OK( mp_init(&x) );
  344. CHECK_MPI_OK( mp_init(&k) );
  345. CHECK_MPI_OK( mp_init(&r) );
  346. CHECK_MPI_OK( mp_init(&s) );
  347. /*
  348. ** Convert stored PQG and private key into MPI integers.
  349. */
  350. SECITEM_TO_MPINT(key->params.prime, &p);
  351. SECITEM_TO_MPINT(key->params.subPrime, &q);
  352. SECITEM_TO_MPINT(key->params.base, &g);
  353. SECITEM_TO_MPINT(key->privateValue, &x);
  354. OCTETS_TO_MPINT(kb, &k, DSA_SUBPRIME_LEN);
  355. /*
  356. ** FIPS 186-1, Section 5, Step 1
  357. **
  358. ** r = (g**k mod p) mod q
  359. */
  360. CHECK_MPI_OK( mp_exptmod(&g, &k, &p, &r) ); /* r = g**k mod p */
  361. CHECK_MPI_OK( mp_mod(&r, &q, &r) ); /* r = r mod q */
  362. /*
  363. ** FIPS 186-1, Section 5, Step 2
  364. **
  365. ** s = (k**-1 * (SHA1(M) + x*r)) mod q
  366. */
  367. SECITEM_TO_MPINT(*digest, &s); /* s = SHA1(M) */
  368. CHECK_MPI_OK( mp_invmod(&k, &q, &k) ); /* k = k**-1 mod q */
  369. CHECK_MPI_OK( mp_mulmod(&x, &r, &q, &x) ); /* x = x * r mod q */
  370. CHECK_MPI_OK( mp_addmod(&s, &x, &q, &s) ); /* s = s + x mod q */
  371. CHECK_MPI_OK( mp_mulmod(&s, &k, &q, &s) ); /* s = s * k mod q */
  372. /*
  373. ** verify r != 0 and s != 0
  374. ** mentioned as optional in FIPS 186-1.
  375. */
  376. if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) {
  377. PORT_SetError(SEC_ERROR_NEED_RANDOM);
  378. rv = SECFailure;
  379. goto cleanup;
  380. }
  381. /*
  382. ** Step 4
  383. **
  384. ** Signature is tuple (r, s)
  385. */
  386. err = mp_to_fixlen_octets(&r, signature->data, DSA_SUBPRIME_LEN);
  387. if (err < 0) goto cleanup;
  388. err = mp_to_fixlen_octets(&s, signature->data + DSA_SUBPRIME_LEN,
  389. DSA_SUBPRIME_LEN);
  390. if (err < 0) goto cleanup;
  391. err = MP_OKAY;
  392. signature->len = DSA_SIGNATURE_LEN;
  393. cleanup:
  394. mp_clear(&p);
  395. mp_clear(&q);
  396. mp_clear(&g);
  397. mp_clear(&x);
  398. mp_clear(&k);
  399. mp_clear(&r);
  400. mp_clear(&s);
  401. if (err) {
  402. translate_mpi_error(err);
  403. rv = SECFailure;
  404. }
  405. return rv;
  406. }
  407. /* signature is caller-supplied buffer of at least 40 bytes.
  408. ** On input, signature->len == size of buffer to hold signature.
  409. ** digest->len == size of digest.
  410. ** On output, signature->len == size of signature in buffer.
  411. ** Uses a random seed.
  412. */
  413. SECStatus
  414. DSA_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest)
  415. {
  416. SECStatus rv;
  417. int retries = 10;
  418. unsigned char kSeed[DSA_SUBPRIME_LEN];
  419. unsigned int kSeedLen = 0;
  420. unsigned int i;
  421. PRBool good;
  422. PORT_SetError(0);
  423. do {
  424. rv = dsa_GenerateGlobalRandomBytes(&key->params.subPrime,
  425. kSeed, &kSeedLen, sizeof kSeed);
  426. if (rv != SECSuccess)
  427. break;
  428. if (kSeedLen != DSA_SUBPRIME_LEN) {
  429. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  430. rv = SECFailure;
  431. break;
  432. }
  433. /* Disallow a value of 0 for k. */
  434. good = PR_FALSE;
  435. for (i = 0; i < kSeedLen; i++) {
  436. if (kSeed[i] != 0) {
  437. good = PR_TRUE;
  438. break;
  439. }
  440. }
  441. if (!good) {
  442. PORT_SetError(SEC_ERROR_NEED_RANDOM);
  443. rv = SECFailure;
  444. continue;
  445. }
  446. rv = dsa_SignDigest(key, signature, digest, kSeed);
  447. } while (rv != SECSuccess && PORT_GetError() == SEC_ERROR_NEED_RANDOM &&
  448. --retries > 0);
  449. return rv;
  450. }
  451. /* For FIPS compliance testing. Seed must be exactly 20 bytes. */
  452. SECStatus
  453. DSA_SignDigestWithSeed(DSAPrivateKey * key,
  454. SECItem * signature,
  455. const SECItem * digest,
  456. const unsigned char * seed)
  457. {
  458. SECStatus rv;
  459. rv = dsa_SignDigest(key, signature, digest, seed);
  460. return rv;
  461. }
  462. /* signature is caller-supplied buffer of at least 20 bytes.
  463. ** On input, signature->len == size of buffer to hold signature.
  464. ** digest->len == size of digest.
  465. */
  466. SECStatus
  467. DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature,
  468. const SECItem *digest)
  469. {
  470. /* FIPS-compliance dictates that digest is a SHA1 hash. */
  471. mp_int p, q, g; /* PQG parameters */
  472. mp_int r_, s_; /* tuple (r', s') is received signature) */
  473. mp_int u1, u2, v, w; /* intermediate values used in verification */
  474. mp_int y; /* public key */
  475. mp_err err;
  476. SECStatus verified = SECFailure;
  477. /* Check args. */
  478. if (!key || !signature || !digest ||
  479. (signature->len != DSA_SIGNATURE_LEN) ||
  480. (digest->len != SHA1_LENGTH)) {
  481. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  482. return SECFailure;
  483. }
  484. /* Initialize MPI integers. */
  485. MP_DIGITS(&p) = 0;
  486. MP_DIGITS(&q) = 0;
  487. MP_DIGITS(&g) = 0;
  488. MP_DIGITS(&y) = 0;
  489. MP_DIGITS(&r_) = 0;
  490. MP_DIGITS(&s_) = 0;
  491. MP_DIGITS(&u1) = 0;
  492. MP_DIGITS(&u2) = 0;
  493. MP_DIGITS(&v) = 0;
  494. MP_DIGITS(&w) = 0;
  495. CHECK_MPI_OK( mp_init(&p) );
  496. CHECK_MPI_OK( mp_init(&q) );
  497. CHECK_MPI_OK( mp_init(&g) );
  498. CHECK_MPI_OK( mp_init(&y) );
  499. CHECK_MPI_OK( mp_init(&r_) );
  500. CHECK_MPI_OK( mp_init(&s_) );
  501. CHECK_MPI_OK( mp_init(&u1) );
  502. CHECK_MPI_OK( mp_init(&u2) );
  503. CHECK_MPI_OK( mp_init(&v) );
  504. CHECK_MPI_OK( mp_init(&w) );
  505. /*
  506. ** Convert stored PQG and public key into MPI integers.
  507. */
  508. SECITEM_TO_MPINT(key->params.prime, &p);
  509. SECITEM_TO_MPINT(key->params.subPrime, &q);
  510. SECITEM_TO_MPINT(key->params.base, &g);
  511. SECITEM_TO_MPINT(key->publicValue, &y);
  512. /*
  513. ** Convert received signature (r', s') into MPI integers.
  514. */
  515. OCTETS_TO_MPINT(signature->data, &r_, DSA_SUBPRIME_LEN);
  516. OCTETS_TO_MPINT(signature->data + DSA_SUBPRIME_LEN, &s_, DSA_SUBPRIME_LEN);
  517. /*
  518. ** Verify that 0 < r' < q and 0 < s' < q
  519. */
  520. if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
  521. mp_cmp(&r_, &q) >= 0 || mp_cmp(&s_, &q) >= 0) {
  522. /* err is zero here. */
  523. PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  524. goto cleanup; /* will return verified == SECFailure */
  525. }
  526. /*
  527. ** FIPS 186-1, Section 6, Step 1
  528. **
  529. ** w = (s')**-1 mod q
  530. */
  531. CHECK_MPI_OK( mp_invmod(&s_, &q, &w) ); /* w = (s')**-1 mod q */
  532. /*
  533. ** FIPS 186-1, Section 6, Step 2
  534. **
  535. ** u1 = ((SHA1(M')) * w) mod q
  536. */
  537. SECITEM_TO_MPINT(*digest, &u1); /* u1 = SHA1(M') */
  538. CHECK_MPI_OK( mp_mulmod(&u1, &w, &q, &u1) ); /* u1 = u1 * w mod q */
  539. /*
  540. ** FIPS 186-1, Section 6, Step 3
  541. **
  542. ** u2 = ((r') * w) mod q
  543. */
  544. CHECK_MPI_OK( mp_mulmod(&r_, &w, &q, &u2) );
  545. /*
  546. ** FIPS 186-1, Section 6, Step 4
  547. **
  548. ** v = ((g**u1 * y**u2) mod p) mod q
  549. */
  550. CHECK_MPI_OK( mp_exptmod(&g, &u1, &p, &g) ); /* g = g**u1 mod p */
  551. CHECK_MPI_OK( mp_exptmod(&y, &u2, &p, &y) ); /* y = y**u2 mod p */
  552. CHECK_MPI_OK( mp_mulmod(&g, &y, &p, &v) ); /* v = g * y mod p */
  553. CHECK_MPI_OK( mp_mod(&v, &q, &v) ); /* v = v mod q */
  554. /*
  555. ** Verification: v == r'
  556. */
  557. if (mp_cmp(&v, &r_)) {
  558. PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  559. verified = SECFailure; /* Signature failed to verify. */
  560. } else {
  561. verified = SECSuccess; /* Signature verified. */
  562. }
  563. cleanup:
  564. mp_clear(&p);
  565. mp_clear(&q);
  566. mp_clear(&g);
  567. mp_clear(&y);
  568. mp_clear(&r_);
  569. mp_clear(&s_);
  570. mp_clear(&u1);
  571. mp_clear(&u2);
  572. mp_clear(&v);
  573. mp_clear(&w);
  574. if (err) {
  575. translate_mpi_error(err);
  576. }
  577. return verified;
  578. }