eap_pwd_common.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * EAP server/peer: EAP-pwd shared routines
  3. * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include "includes.h"
  9. #include "common.h"
  10. #include "crypto/sha256.h"
  11. #include "crypto/crypto.h"
  12. #include "eap_defs.h"
  13. #include "eap_pwd_common.h"
  14. /* The random function H(x) = HMAC-SHA256(0^32, x) */
  15. struct crypto_hash * eap_pwd_h_init(void)
  16. {
  17. u8 allzero[SHA256_MAC_LEN];
  18. os_memset(allzero, 0, SHA256_MAC_LEN);
  19. return crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256, allzero,
  20. SHA256_MAC_LEN);
  21. }
  22. void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len)
  23. {
  24. crypto_hash_update(hash, data, len);
  25. }
  26. void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest)
  27. {
  28. size_t len = SHA256_MAC_LEN;
  29. crypto_hash_finish(hash, digest, &len);
  30. }
  31. /* a counter-based KDF based on NIST SP800-108 */
  32. static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label,
  33. size_t labellen, u8 *result, size_t resultbitlen)
  34. {
  35. struct crypto_hash *hash;
  36. u8 digest[SHA256_MAC_LEN];
  37. u16 i, ctr, L;
  38. size_t resultbytelen, len = 0, mdlen;
  39. resultbytelen = (resultbitlen + 7) / 8;
  40. ctr = 0;
  41. L = htons(resultbitlen);
  42. while (len < resultbytelen) {
  43. ctr++;
  44. i = htons(ctr);
  45. hash = crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256,
  46. key, keylen);
  47. if (hash == NULL)
  48. return -1;
  49. if (ctr > 1)
  50. crypto_hash_update(hash, digest, SHA256_MAC_LEN);
  51. crypto_hash_update(hash, (u8 *) &i, sizeof(u16));
  52. crypto_hash_update(hash, label, labellen);
  53. crypto_hash_update(hash, (u8 *) &L, sizeof(u16));
  54. mdlen = SHA256_MAC_LEN;
  55. if (crypto_hash_finish(hash, digest, &mdlen) < 0)
  56. return -1;
  57. if ((len + mdlen) > resultbytelen)
  58. os_memcpy(result + len, digest, resultbytelen - len);
  59. else
  60. os_memcpy(result + len, digest, mdlen);
  61. len += mdlen;
  62. }
  63. /* since we're expanding to a bit length, mask off the excess */
  64. if (resultbitlen % 8) {
  65. u8 mask = 0xff;
  66. mask <<= (8 - (resultbitlen % 8));
  67. result[resultbytelen - 1] &= mask;
  68. }
  69. return 0;
  70. }
  71. /*
  72. * compute a "random" secret point on an elliptic curve based
  73. * on the password and identities.
  74. */
  75. int compute_password_element(EAP_PWD_group *grp, u16 num,
  76. const u8 *password, size_t password_len,
  77. const u8 *id_server, size_t id_server_len,
  78. const u8 *id_peer, size_t id_peer_len,
  79. const u8 *token)
  80. {
  81. BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
  82. struct crypto_hash *hash;
  83. unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
  84. int nid, is_odd, ret = 0;
  85. size_t primebytelen, primebitlen;
  86. switch (num) { /* from IANA registry for IKE D-H groups */
  87. case 19:
  88. nid = NID_X9_62_prime256v1;
  89. break;
  90. case 20:
  91. nid = NID_secp384r1;
  92. break;
  93. case 21:
  94. nid = NID_secp521r1;
  95. break;
  96. #ifndef OPENSSL_IS_BORINGSSL
  97. case 25:
  98. nid = NID_X9_62_prime192v1;
  99. break;
  100. #endif /* OPENSSL_IS_BORINGSSL */
  101. case 26:
  102. nid = NID_secp224r1;
  103. break;
  104. #ifdef NID_brainpoolP224r1
  105. case 27:
  106. nid = NID_brainpoolP224r1;
  107. break;
  108. #endif /* NID_brainpoolP224r1 */
  109. #ifdef NID_brainpoolP256r1
  110. case 28:
  111. nid = NID_brainpoolP256r1;
  112. break;
  113. #endif /* NID_brainpoolP256r1 */
  114. #ifdef NID_brainpoolP384r1
  115. case 29:
  116. nid = NID_brainpoolP384r1;
  117. break;
  118. #endif /* NID_brainpoolP384r1 */
  119. #ifdef NID_brainpoolP512r1
  120. case 30:
  121. nid = NID_brainpoolP512r1;
  122. break;
  123. #endif /* NID_brainpoolP512r1 */
  124. default:
  125. wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num);
  126. return -1;
  127. }
  128. grp->pwe = NULL;
  129. grp->order = NULL;
  130. grp->prime = NULL;
  131. if ((grp->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
  132. wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP");
  133. goto fail;
  134. }
  135. if (((rnd = BN_new()) == NULL) ||
  136. ((cofactor = BN_new()) == NULL) ||
  137. ((grp->pwe = EC_POINT_new(grp->group)) == NULL) ||
  138. ((grp->order = BN_new()) == NULL) ||
  139. ((grp->prime = BN_new()) == NULL) ||
  140. ((x_candidate = BN_new()) == NULL)) {
  141. wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
  142. goto fail;
  143. }
  144. if (!EC_GROUP_get_curve_GFp(grp->group, grp->prime, NULL, NULL, NULL))
  145. {
  146. wpa_printf(MSG_INFO, "EAP-pwd: unable to get prime for GFp "
  147. "curve");
  148. goto fail;
  149. }
  150. if (!EC_GROUP_get_order(grp->group, grp->order, NULL)) {
  151. wpa_printf(MSG_INFO, "EAP-pwd: unable to get order for curve");
  152. goto fail;
  153. }
  154. if (!EC_GROUP_get_cofactor(grp->group, cofactor, NULL)) {
  155. wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for "
  156. "curve");
  157. goto fail;
  158. }
  159. primebitlen = BN_num_bits(grp->prime);
  160. primebytelen = BN_num_bytes(grp->prime);
  161. if ((prfbuf = os_malloc(primebytelen)) == NULL) {
  162. wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf "
  163. "buffer");
  164. goto fail;
  165. }
  166. os_memset(prfbuf, 0, primebytelen);
  167. ctr = 0;
  168. while (1) {
  169. if (ctr > 30) {
  170. wpa_printf(MSG_INFO, "EAP-pwd: unable to find random "
  171. "point on curve for group %d, something's "
  172. "fishy", num);
  173. goto fail;
  174. }
  175. ctr++;
  176. /*
  177. * compute counter-mode password value and stretch to prime
  178. * pwd-seed = H(token | peer-id | server-id | password |
  179. * counter)
  180. */
  181. hash = eap_pwd_h_init();
  182. if (hash == NULL)
  183. goto fail;
  184. eap_pwd_h_update(hash, token, sizeof(u32));
  185. eap_pwd_h_update(hash, id_peer, id_peer_len);
  186. eap_pwd_h_update(hash, id_server, id_server_len);
  187. eap_pwd_h_update(hash, password, password_len);
  188. eap_pwd_h_update(hash, &ctr, sizeof(ctr));
  189. eap_pwd_h_final(hash, pwe_digest);
  190. BN_bin2bn(pwe_digest, SHA256_MAC_LEN, rnd);
  191. if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN,
  192. (u8 *) "EAP-pwd Hunting And Pecking",
  193. os_strlen("EAP-pwd Hunting And Pecking"),
  194. prfbuf, primebitlen) < 0)
  195. goto fail;
  196. BN_bin2bn(prfbuf, primebytelen, x_candidate);
  197. /*
  198. * eap_pwd_kdf() returns a string of bits 0..primebitlen but
  199. * BN_bin2bn will treat that string of bits as a big endian
  200. * number. If the primebitlen is not an even multiple of 8
  201. * then excessive bits-- those _after_ primebitlen-- so now
  202. * we have to shift right the amount we masked off.
  203. */
  204. if (primebitlen % 8)
  205. BN_rshift(x_candidate, x_candidate,
  206. (8 - (primebitlen % 8)));
  207. if (BN_ucmp(x_candidate, grp->prime) >= 0)
  208. continue;
  209. wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate",
  210. prfbuf, primebytelen);
  211. /*
  212. * need to unambiguously identify the solution, if there is
  213. * one...
  214. */
  215. if (BN_is_odd(rnd))
  216. is_odd = 1;
  217. else
  218. is_odd = 0;
  219. /*
  220. * solve the quadratic equation, if it's not solvable then we
  221. * don't have a point
  222. */
  223. if (!EC_POINT_set_compressed_coordinates_GFp(grp->group,
  224. grp->pwe,
  225. x_candidate,
  226. is_odd, NULL))
  227. continue;
  228. /*
  229. * If there's a solution to the equation then the point must be
  230. * on the curve so why check again explicitly? OpenSSL code
  231. * says this is required by X9.62. We're not X9.62 but it can't
  232. * hurt just to be sure.
  233. */
  234. if (!EC_POINT_is_on_curve(grp->group, grp->pwe, NULL)) {
  235. wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
  236. continue;
  237. }
  238. if (BN_cmp(cofactor, BN_value_one())) {
  239. /* make sure the point is not in a small sub-group */
  240. if (!EC_POINT_mul(grp->group, grp->pwe, NULL, grp->pwe,
  241. cofactor, NULL)) {
  242. wpa_printf(MSG_INFO, "EAP-pwd: cannot "
  243. "multiply generator by order");
  244. continue;
  245. }
  246. if (EC_POINT_is_at_infinity(grp->group, grp->pwe)) {
  247. wpa_printf(MSG_INFO, "EAP-pwd: point is at "
  248. "infinity");
  249. continue;
  250. }
  251. }
  252. /* if we got here then we have a new generator. */
  253. break;
  254. }
  255. wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr);
  256. grp->group_num = num;
  257. if (0) {
  258. fail:
  259. EC_GROUP_free(grp->group);
  260. grp->group = NULL;
  261. EC_POINT_clear_free(grp->pwe);
  262. grp->pwe = NULL;
  263. BN_clear_free(grp->order);
  264. grp->order = NULL;
  265. BN_clear_free(grp->prime);
  266. grp->prime = NULL;
  267. ret = 1;
  268. }
  269. /* cleanliness and order.... */
  270. BN_clear_free(cofactor);
  271. BN_clear_free(x_candidate);
  272. BN_clear_free(rnd);
  273. os_free(prfbuf);
  274. return ret;
  275. }
  276. int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
  277. const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
  278. const u8 *confirm_peer, const u8 *confirm_server,
  279. const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id)
  280. {
  281. struct crypto_hash *hash;
  282. u8 mk[SHA256_MAC_LEN], *cruft;
  283. u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
  284. int offset;
  285. if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL)
  286. return -1;
  287. /*
  288. * first compute the session-id = TypeCode | H(ciphersuite | scal_p |
  289. * scal_s)
  290. */
  291. session_id[0] = EAP_TYPE_PWD;
  292. hash = eap_pwd_h_init();
  293. if (hash == NULL) {
  294. os_free(cruft);
  295. return -1;
  296. }
  297. eap_pwd_h_update(hash, (const u8 *) ciphersuite, sizeof(u32));
  298. offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
  299. os_memset(cruft, 0, BN_num_bytes(grp->prime));
  300. BN_bn2bin(peer_scalar, cruft + offset);
  301. eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
  302. offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar);
  303. os_memset(cruft, 0, BN_num_bytes(grp->prime));
  304. BN_bn2bin(server_scalar, cruft + offset);
  305. eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
  306. eap_pwd_h_final(hash, &session_id[1]);
  307. /* then compute MK = H(k | confirm-peer | confirm-server) */
  308. hash = eap_pwd_h_init();
  309. if (hash == NULL) {
  310. os_free(cruft);
  311. return -1;
  312. }
  313. offset = BN_num_bytes(grp->prime) - BN_num_bytes(k);
  314. os_memset(cruft, 0, BN_num_bytes(grp->prime));
  315. BN_bn2bin(k, cruft + offset);
  316. eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->prime));
  317. os_free(cruft);
  318. eap_pwd_h_update(hash, confirm_peer, SHA256_MAC_LEN);
  319. eap_pwd_h_update(hash, confirm_server, SHA256_MAC_LEN);
  320. eap_pwd_h_final(hash, mk);
  321. /* stretch the mk with the session-id to get MSK | EMSK */
  322. if (eap_pwd_kdf(mk, SHA256_MAC_LEN,
  323. session_id, SHA256_MAC_LEN + 1,
  324. msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8) < 0) {
  325. return -1;
  326. }
  327. os_memcpy(msk, msk_emsk, EAP_MSK_LEN);
  328. os_memcpy(emsk, msk_emsk + EAP_MSK_LEN, EAP_EMSK_LEN);
  329. return 1;
  330. }