/security/nss/lib/freebl/jpake.c

http://github.com/zpao/v8monkey · C · 526 lines · 403 code · 64 blank · 59 comment · 145 complexity · d94893b51136edbcd7f208406bd72f2f MD5 · raw file

  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is the Netscape security libraries.
  15. *
  16. * The Initial Developer of the Original Code is Mozilla Fonudation.
  17. * Portions created by the Initial Developer are Copyright (C) 2010
  18. * the Initial Developer. All Rights Reserved.
  19. *
  20. * Contributor(s):
  21. *
  22. * Alternatively, the contents of this file may be used under the terms of
  23. * either the GNU General Public License Version 2 or later (the "GPL"), or
  24. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  25. * in which case the provisions of the GPL or the LGPL are applicable instead
  26. * of those above. If you wish to allow use of your version of this file only
  27. * under the terms of either the GPL or the LGPL, and not to allow others to
  28. * use your version of this file under the terms of the MPL, indicate your
  29. * decision by deleting the provisions above and replace them with the notice
  30. * and other provisions required by the GPL or the LGPL. If you do not delete
  31. * the provisions above, a recipient may use your version of this file under
  32. * the terms of any one of the MPL, the GPL or the LGPL.
  33. *
  34. * ***** END LICENSE BLOCK ***** */
  35. #ifdef FREEBL_NO_DEPEND
  36. #include "stubs.h"
  37. #endif
  38. #include "blapi.h"
  39. #include "secerr.h"
  40. #include "secitem.h"
  41. #include "secmpi.h"
  42. /* Hash an item's length and then its value. Only items smaller than 2^16 bytes
  43. * are allowed. Lengths are hashed in network byte order. This is designed
  44. * to match the OpenSSL J-PAKE implementation.
  45. */
  46. static mp_err
  47. hashSECItem(HASHContext * hash, const SECItem * it)
  48. {
  49. unsigned char length[2];
  50. if (it->len > 0xffff)
  51. return MP_BADARG;
  52. length[0] = (unsigned char) (it->len >> 8);
  53. length[1] = (unsigned char) (it->len);
  54. hash->hashobj->update(hash->hash_context, length, 2);
  55. hash->hashobj->update(hash->hash_context, it->data, it->len);
  56. return MP_OKAY;
  57. }
  58. /* Hash all public components of the signature, each prefixed with its
  59. length, and then convert the hash to an mp_int. */
  60. static mp_err
  61. hashPublicParams(HASH_HashType hashType, const SECItem * g,
  62. const SECItem * gv, const SECItem * gx,
  63. const SECItem * signerID, mp_int * h)
  64. {
  65. mp_err err;
  66. unsigned char hBuf[HASH_LENGTH_MAX];
  67. SECItem hItem;
  68. HASHContext hash;
  69. hash.hashobj = HASH_GetRawHashObject(hashType);
  70. if (hash.hashobj == NULL || hash.hashobj->length > sizeof hBuf) {
  71. return MP_BADARG;
  72. }
  73. hash.hash_context = hash.hashobj->create();
  74. if (hash.hash_context == NULL) {
  75. return MP_MEM;
  76. }
  77. hItem.data = hBuf;
  78. hItem.len = hash.hashobj->length;
  79. hash.hashobj->begin(hash.hash_context);
  80. CHECK_MPI_OK( hashSECItem(&hash, g) );
  81. CHECK_MPI_OK( hashSECItem(&hash, gv) );
  82. CHECK_MPI_OK( hashSECItem(&hash, gx) );
  83. CHECK_MPI_OK( hashSECItem(&hash, signerID) );
  84. hash.hashobj->end(hash.hash_context, hItem.data, &hItem.len,
  85. sizeof hBuf);
  86. SECITEM_TO_MPINT(hItem, h);
  87. cleanup:
  88. if (hash.hash_context != NULL) {
  89. hash.hashobj->destroy(hash.hash_context, PR_TRUE);
  90. }
  91. return err;
  92. }
  93. /* Generate a Schnorr signature for round 1 or round 2 */
  94. SECStatus
  95. JPAKE_Sign(PLArenaPool * arena, const PQGParams * pqg, HASH_HashType hashType,
  96. const SECItem * signerID, const SECItem * x,
  97. const SECItem * testRandom, const SECItem * gxIn, SECItem * gxOut,
  98. SECItem * gv, SECItem * r)
  99. {
  100. SECStatus rv = SECSuccess;
  101. mp_err err;
  102. mp_int p;
  103. mp_int q;
  104. mp_int g;
  105. mp_int X;
  106. mp_int GX;
  107. mp_int V;
  108. mp_int GV;
  109. mp_int h;
  110. mp_int tmp;
  111. mp_int R;
  112. SECItem v;
  113. if (!arena ||
  114. !pqg || !pqg->prime.data || pqg->prime.len == 0 ||
  115. !pqg->subPrime.data || pqg->subPrime.len == 0 ||
  116. !pqg->base.data || pqg->base.len == 0 ||
  117. !signerID || !signerID->data || signerID->len == 0 ||
  118. !x || !x->data || x->len == 0 ||
  119. (testRandom && (!testRandom->data || testRandom->len == 0)) ||
  120. (gxIn == NULL && (!gxOut || gxOut->data != NULL)) ||
  121. (gxIn != NULL && (!gxIn->data || gxIn->len == 0 || gxOut != NULL)) ||
  122. !gv || gv->data != NULL ||
  123. !r || r->data != NULL) {
  124. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  125. return SECFailure;
  126. }
  127. MP_DIGITS(&p) = 0;
  128. MP_DIGITS(&q) = 0;
  129. MP_DIGITS(&g) = 0;
  130. MP_DIGITS(&X) = 0;
  131. MP_DIGITS(&GX) = 0;
  132. MP_DIGITS(&V) = 0;
  133. MP_DIGITS(&GV) = 0;
  134. MP_DIGITS(&h) = 0;
  135. MP_DIGITS(&tmp) = 0;
  136. MP_DIGITS(&R) = 0;
  137. CHECK_MPI_OK( mp_init(&p) );
  138. CHECK_MPI_OK( mp_init(&q) );
  139. CHECK_MPI_OK( mp_init(&g) );
  140. CHECK_MPI_OK( mp_init(&X) );
  141. CHECK_MPI_OK( mp_init(&GX) );
  142. CHECK_MPI_OK( mp_init(&V) );
  143. CHECK_MPI_OK( mp_init(&GV) );
  144. CHECK_MPI_OK( mp_init(&h) );
  145. CHECK_MPI_OK( mp_init(&tmp) );
  146. CHECK_MPI_OK( mp_init(&R) );
  147. SECITEM_TO_MPINT(pqg->prime, &p);
  148. SECITEM_TO_MPINT(pqg->subPrime, &q);
  149. SECITEM_TO_MPINT(pqg->base, &g);
  150. SECITEM_TO_MPINT(*x, &X);
  151. /* gx = g^x */
  152. if (gxIn == NULL) {
  153. CHECK_MPI_OK( mp_exptmod(&g, &X, &p, &GX) );
  154. MPINT_TO_SECITEM(&GX, gxOut, arena);
  155. gxIn = gxOut;
  156. } else {
  157. SECITEM_TO_MPINT(*gxIn, &GX);
  158. }
  159. /* v is a random value in the q subgroup */
  160. if (testRandom == NULL) {
  161. v.data = NULL;
  162. rv = DSA_NewRandom(arena, &pqg->subPrime, &v);
  163. if (rv != SECSuccess) {
  164. goto cleanup;
  165. }
  166. } else {
  167. v.data = testRandom->data;
  168. v.len = testRandom->len;
  169. }
  170. SECITEM_TO_MPINT(v, &V);
  171. /* gv = g^v (mod q), random v, 1 <= v < q */
  172. CHECK_MPI_OK( mp_exptmod(&g, &V, &p, &GV) );
  173. MPINT_TO_SECITEM(&GV, gv, arena);
  174. /* h = H(g, gv, gx, signerID) */
  175. CHECK_MPI_OK( hashPublicParams(hashType, &pqg->base, gv, gxIn, signerID,
  176. &h) );
  177. /* r = v - x*h (mod q) */
  178. CHECK_MPI_OK( mp_mulmod(&X, &h, &q, &tmp) );
  179. CHECK_MPI_OK( mp_submod(&V, &tmp, &q, &R) );
  180. MPINT_TO_SECITEM(&R, r, arena);
  181. cleanup:
  182. mp_clear(&p);
  183. mp_clear(&q);
  184. mp_clear(&g);
  185. mp_clear(&X);
  186. mp_clear(&GX);
  187. mp_clear(&V);
  188. mp_clear(&GV);
  189. mp_clear(&h);
  190. mp_clear(&tmp);
  191. mp_clear(&R);
  192. if (rv == SECSuccess && err != MP_OKAY) {
  193. MP_TO_SEC_ERROR(err);
  194. rv = SECFailure;
  195. }
  196. return rv;
  197. }
  198. /* Verify a Schnorr signature generated by the peer in round 1 or round 2. */
  199. SECStatus
  200. JPAKE_Verify(PLArenaPool * arena, const PQGParams * pqg, HASH_HashType hashType,
  201. const SECItem * signerID, const SECItem * peerID,
  202. const SECItem * gx, const SECItem * gv, const SECItem * r)
  203. {
  204. SECStatus rv = SECSuccess;
  205. mp_err err;
  206. mp_int p;
  207. mp_int q;
  208. mp_int g;
  209. mp_int p_minus_1;
  210. mp_int GX;
  211. mp_int h;
  212. mp_int one;
  213. mp_int R;
  214. mp_int gr;
  215. mp_int gxh;
  216. mp_int gr_gxh;
  217. SECItem calculated;
  218. if (!arena ||
  219. !pqg || !pqg->prime.data || pqg->prime.len == 0 ||
  220. !pqg->subPrime.data || pqg->subPrime.len == 0 ||
  221. !pqg->base.data || pqg->base.len == 0 ||
  222. !signerID || !signerID->data || signerID->len == 0 ||
  223. !peerID || !peerID->data || peerID->len == 0 ||
  224. !gx || !gx->data || gx->len == 0 ||
  225. !gv || !gv->data || gv->len == 0 ||
  226. !r || !r->data || r->len == 0 ||
  227. SECITEM_CompareItem(signerID, peerID) == SECEqual) {
  228. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  229. return SECFailure;
  230. }
  231. MP_DIGITS(&p) = 0;
  232. MP_DIGITS(&q) = 0;
  233. MP_DIGITS(&g) = 0;
  234. MP_DIGITS(&p_minus_1) = 0;
  235. MP_DIGITS(&GX) = 0;
  236. MP_DIGITS(&h) = 0;
  237. MP_DIGITS(&one) = 0;
  238. MP_DIGITS(&R) = 0;
  239. MP_DIGITS(&gr) = 0;
  240. MP_DIGITS(&gxh) = 0;
  241. MP_DIGITS(&gr_gxh) = 0;
  242. calculated.data = NULL;
  243. CHECK_MPI_OK( mp_init(&p) );
  244. CHECK_MPI_OK( mp_init(&q) );
  245. CHECK_MPI_OK( mp_init(&g) );
  246. CHECK_MPI_OK( mp_init(&p_minus_1) );
  247. CHECK_MPI_OK( mp_init(&GX) );
  248. CHECK_MPI_OK( mp_init(&h) );
  249. CHECK_MPI_OK( mp_init(&one) );
  250. CHECK_MPI_OK( mp_init(&R) );
  251. CHECK_MPI_OK( mp_init(&gr) );
  252. CHECK_MPI_OK( mp_init(&gxh) );
  253. CHECK_MPI_OK( mp_init(&gr_gxh) );
  254. SECITEM_TO_MPINT(pqg->prime, &p);
  255. SECITEM_TO_MPINT(pqg->subPrime, &q);
  256. SECITEM_TO_MPINT(pqg->base, &g);
  257. SECITEM_TO_MPINT(*gx, &GX);
  258. SECITEM_TO_MPINT(*r, &R);
  259. CHECK_MPI_OK( mp_sub_d(&p, 1, &p_minus_1) );
  260. CHECK_MPI_OK( mp_exptmod(&GX, &q, &p, &one) );
  261. /* Check g^x is in [1, p-2], R is in [0, q-1], and (g^x)^q mod p == 1 */
  262. if (!(mp_cmp_z(&GX) > 0 &&
  263. mp_cmp(&GX, &p_minus_1) < 0 &&
  264. mp_cmp(&R, &q) < 0 &&
  265. mp_cmp_d(&one, 1) == 0)) {
  266. goto badSig;
  267. }
  268. CHECK_MPI_OK( hashPublicParams(hashType, &pqg->base, gv, gx, peerID,
  269. &h) );
  270. /* Calculate g^v = g^r * g^x^h */
  271. CHECK_MPI_OK( mp_exptmod(&g, &R, &p, &gr) );
  272. CHECK_MPI_OK( mp_exptmod(&GX, &h, &p, &gxh) );
  273. CHECK_MPI_OK( mp_mulmod(&gr, &gxh, &p, &gr_gxh) );
  274. /* Compare calculated g^v to given g^v */
  275. MPINT_TO_SECITEM(&gr_gxh, &calculated, arena);
  276. if (calculated.len == gv->len &&
  277. NSS_SecureMemcmp(calculated.data, gv->data, calculated.len) == 0) {
  278. rv = SECSuccess;
  279. } else {
  280. badSig: PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  281. rv = SECFailure;
  282. }
  283. cleanup:
  284. mp_clear(&p);
  285. mp_clear(&q);
  286. mp_clear(&g);
  287. mp_clear(&p_minus_1);
  288. mp_clear(&GX);
  289. mp_clear(&h);
  290. mp_clear(&one);
  291. mp_clear(&R);
  292. mp_clear(&gr);
  293. mp_clear(&gxh);
  294. mp_clear(&gr_gxh);
  295. if (rv == SECSuccess && err != MP_OKAY) {
  296. MP_TO_SEC_ERROR(err);
  297. rv = SECFailure;
  298. }
  299. return rv;
  300. }
  301. /* Calculate base = gx1*gx3*gx4 (mod p), i.e. g^(x1+x3+x4) (mod p) */
  302. static mp_err
  303. jpake_Round2Base(const SECItem * gx1, const SECItem * gx3,
  304. const SECItem * gx4, const mp_int * p, mp_int * base)
  305. {
  306. mp_err err;
  307. mp_int GX1;
  308. mp_int GX3;
  309. mp_int GX4;
  310. mp_int tmp;
  311. MP_DIGITS(&GX1) = 0;
  312. MP_DIGITS(&GX3) = 0;
  313. MP_DIGITS(&GX4) = 0;
  314. MP_DIGITS(&tmp) = 0;
  315. CHECK_MPI_OK( mp_init(&GX1) );
  316. CHECK_MPI_OK( mp_init(&GX3) );
  317. CHECK_MPI_OK( mp_init(&GX4) );
  318. CHECK_MPI_OK( mp_init(&tmp) );
  319. SECITEM_TO_MPINT(*gx1, &GX1);
  320. SECITEM_TO_MPINT(*gx3, &GX3);
  321. SECITEM_TO_MPINT(*gx4, &GX4);
  322. /* In round 2, the peer/attacker sends us g^x3 and g^x4 and the protocol
  323. requires that these values are distinct. */
  324. if (mp_cmp(&GX3, &GX4) == 0) {
  325. return MP_BADARG;
  326. }
  327. CHECK_MPI_OK( mp_mul(&GX1, &GX3, &tmp) );
  328. CHECK_MPI_OK( mp_mul(&tmp, &GX4, &tmp) );
  329. CHECK_MPI_OK( mp_mod(&tmp, p, base) );
  330. cleanup:
  331. mp_clear(&GX1);
  332. mp_clear(&GX3);
  333. mp_clear(&GX4);
  334. mp_clear(&tmp);
  335. return err;
  336. }
  337. SECStatus
  338. JPAKE_Round2(PLArenaPool * arena,
  339. const SECItem * p, const SECItem *q, const SECItem * gx1,
  340. const SECItem * gx3, const SECItem * gx4, SECItem * base,
  341. const SECItem * x2, const SECItem * s, SECItem * x2s)
  342. {
  343. mp_err err;
  344. mp_int P;
  345. mp_int Q;
  346. mp_int X2;
  347. mp_int S;
  348. mp_int result;
  349. if (!arena ||
  350. !p || !p->data || p->len == 0 ||
  351. !q || !q->data || q->len == 0 ||
  352. !gx1 || !gx1->data || gx1->len == 0 ||
  353. !gx3 || !gx3->data || gx3->len == 0 ||
  354. !gx4 || !gx4->data || gx4->len == 0 ||
  355. !base || base->data != NULL ||
  356. (x2s != NULL && (x2s->data != NULL ||
  357. !x2 || !x2->data || x2->len == 0 ||
  358. !s || !s->data || s->len == 0))) {
  359. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  360. return SECFailure;
  361. }
  362. MP_DIGITS(&P) = 0;
  363. MP_DIGITS(&Q) = 0;
  364. MP_DIGITS(&X2) = 0;
  365. MP_DIGITS(&S) = 0;
  366. MP_DIGITS(&result) = 0;
  367. CHECK_MPI_OK( mp_init(&P) );
  368. CHECK_MPI_OK( mp_init(&Q) );
  369. CHECK_MPI_OK( mp_init(&result) );
  370. if (x2s != NULL) {
  371. CHECK_MPI_OK( mp_init(&X2) );
  372. CHECK_MPI_OK( mp_init(&S) );
  373. SECITEM_TO_MPINT(*q, &Q);
  374. SECITEM_TO_MPINT(*x2, &X2);
  375. SECITEM_TO_MPINT(*s, &S);
  376. /* S must be in [1, Q-1] */
  377. if (mp_cmp_z(&S) <= 0 || mp_cmp(&S, &Q) >= 0) {
  378. err = MP_BADARG;
  379. goto cleanup;
  380. }
  381. CHECK_MPI_OK( mp_mulmod(&X2, &S, &Q, &result) );
  382. MPINT_TO_SECITEM(&result, x2s, arena);
  383. }
  384. SECITEM_TO_MPINT(*p, &P);
  385. CHECK_MPI_OK( jpake_Round2Base(gx1, gx3, gx4, &P, &result) );
  386. MPINT_TO_SECITEM(&result, base, arena);
  387. cleanup:
  388. mp_clear(&P);
  389. mp_clear(&Q);
  390. mp_clear(&X2);
  391. mp_clear(&S);
  392. mp_clear(&result);
  393. if (err != MP_OKAY) {
  394. MP_TO_SEC_ERROR(err);
  395. return SECFailure;
  396. }
  397. return SECSuccess;
  398. }
  399. SECStatus
  400. JPAKE_Final(PLArenaPool * arena, const SECItem * p, const SECItem * q,
  401. const SECItem * x2, const SECItem * gx4, const SECItem * x2s,
  402. const SECItem * B, SECItem * K)
  403. {
  404. mp_err err;
  405. mp_int P;
  406. mp_int Q;
  407. mp_int tmp;
  408. mp_int exponent;
  409. mp_int divisor;
  410. mp_int base;
  411. if (!arena ||
  412. !p || !p->data || p->len == 0 ||
  413. !q || !q->data || q->len == 0 ||
  414. !x2 || !x2->data || x2->len == 0 ||
  415. !gx4 || !gx4->data || gx4->len == 0 ||
  416. !x2s || !x2s->data || x2s->len == 0 ||
  417. !B || !B->data || B->len == 0 ||
  418. !K || K->data != NULL) {
  419. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  420. return SECFailure;
  421. }
  422. MP_DIGITS(&P) = 0;
  423. MP_DIGITS(&Q) = 0;
  424. MP_DIGITS(&tmp) = 0;
  425. MP_DIGITS(&exponent) = 0;
  426. MP_DIGITS(&divisor) = 0;
  427. MP_DIGITS(&base) = 0;
  428. CHECK_MPI_OK( mp_init(&P) );
  429. CHECK_MPI_OK( mp_init(&Q) );
  430. CHECK_MPI_OK( mp_init(&tmp) );
  431. CHECK_MPI_OK( mp_init(&exponent) );
  432. CHECK_MPI_OK( mp_init(&divisor) );
  433. CHECK_MPI_OK( mp_init(&base) );
  434. /* exponent = -x2s (mod q) */
  435. SECITEM_TO_MPINT(*q, &Q);
  436. SECITEM_TO_MPINT(*x2s, &tmp);
  437. /* q == 0 (mod q), so q - x2s == -x2s (mod q) */
  438. CHECK_MPI_OK( mp_sub(&Q, &tmp, &exponent) );
  439. /* divisor = gx4^-x2s = 1/(gx4^x2s) (mod p) */
  440. SECITEM_TO_MPINT(*p, &P);
  441. SECITEM_TO_MPINT(*gx4, &tmp);
  442. CHECK_MPI_OK( mp_exptmod(&tmp, &exponent, &P, &divisor) );
  443. /* base = B*divisor = B/(gx4^x2s) (mod p) */
  444. SECITEM_TO_MPINT(*B, &tmp);
  445. CHECK_MPI_OK( mp_mulmod(&divisor, &tmp, &P, &base) );
  446. /* tmp = base^x2 (mod p) */
  447. SECITEM_TO_MPINT(*x2, &exponent);
  448. CHECK_MPI_OK( mp_exptmod(&base, &exponent, &P, &tmp) );
  449. MPINT_TO_SECITEM(&tmp, K, arena);
  450. cleanup:
  451. mp_clear(&P);
  452. mp_clear(&Q);
  453. mp_clear(&tmp);
  454. mp_clear(&exponent);
  455. mp_clear(&divisor);
  456. mp_clear(&base);
  457. if (err != MP_OKAY) {
  458. MP_TO_SEC_ERROR(err);
  459. return SECFailure;
  460. }
  461. return SECSuccess;
  462. }