PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/external/wpa_supplicant_8/src/eap_server/eap_server_pax.c

https://gitlab.com/brian0218/rk3066_r-box_android4.2.2_sdk
C | 564 lines | 448 code | 95 blank | 21 comment | 90 complexity | e59e98cd96270195c697addcdc89e509 MD5 | raw file
  1. /*
  2. * hostapd / EAP-PAX (RFC 4746) server
  3. * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
  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/random.h"
  11. #include "eap_server/eap_i.h"
  12. #include "eap_common/eap_pax_common.h"
  13. /*
  14. * Note: only PAX_STD subprotocol is currently supported
  15. *
  16. * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite
  17. * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and
  18. * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits),
  19. * RSAES-OAEP).
  20. */
  21. struct eap_pax_data {
  22. enum { PAX_STD_1, PAX_STD_3, SUCCESS, FAILURE } state;
  23. u8 mac_id;
  24. union {
  25. u8 e[2 * EAP_PAX_RAND_LEN];
  26. struct {
  27. u8 x[EAP_PAX_RAND_LEN]; /* server rand */
  28. u8 y[EAP_PAX_RAND_LEN]; /* client rand */
  29. } r;
  30. } rand;
  31. u8 ak[EAP_PAX_AK_LEN];
  32. u8 mk[EAP_PAX_MK_LEN];
  33. u8 ck[EAP_PAX_CK_LEN];
  34. u8 ick[EAP_PAX_ICK_LEN];
  35. int keys_set;
  36. char *cid;
  37. size_t cid_len;
  38. };
  39. static void * eap_pax_init(struct eap_sm *sm)
  40. {
  41. struct eap_pax_data *data;
  42. data = os_zalloc(sizeof(*data));
  43. if (data == NULL)
  44. return NULL;
  45. data->state = PAX_STD_1;
  46. /*
  47. * TODO: make this configurable once EAP_PAX_HMAC_SHA256_128 is
  48. * supported
  49. */
  50. data->mac_id = EAP_PAX_MAC_HMAC_SHA1_128;
  51. return data;
  52. }
  53. static void eap_pax_reset(struct eap_sm *sm, void *priv)
  54. {
  55. struct eap_pax_data *data = priv;
  56. os_free(data->cid);
  57. os_free(data);
  58. }
  59. static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm,
  60. struct eap_pax_data *data, u8 id)
  61. {
  62. struct wpabuf *req;
  63. struct eap_pax_hdr *pax;
  64. u8 *pos;
  65. wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)");
  66. if (random_get_bytes(data->rand.r.x, EAP_PAX_RAND_LEN)) {
  67. wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
  68. data->state = FAILURE;
  69. return NULL;
  70. }
  71. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
  72. sizeof(*pax) + 2 + EAP_PAX_RAND_LEN +
  73. EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
  74. if (req == NULL) {
  75. wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
  76. "request");
  77. data->state = FAILURE;
  78. return NULL;
  79. }
  80. pax = wpabuf_put(req, sizeof(*pax));
  81. pax->op_code = EAP_PAX_OP_STD_1;
  82. pax->flags = 0;
  83. pax->mac_id = data->mac_id;
  84. pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
  85. pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
  86. wpabuf_put_be16(req, EAP_PAX_RAND_LEN);
  87. wpabuf_put_data(req, data->rand.r.x, EAP_PAX_RAND_LEN);
  88. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: A = X (server rand)",
  89. data->rand.r.x, EAP_PAX_RAND_LEN);
  90. pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
  91. eap_pax_mac(data->mac_id, (u8 *) "", 0,
  92. wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
  93. NULL, 0, NULL, 0, pos);
  94. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
  95. return req;
  96. }
  97. static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm,
  98. struct eap_pax_data *data, u8 id)
  99. {
  100. struct wpabuf *req;
  101. struct eap_pax_hdr *pax;
  102. u8 *pos;
  103. wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (sending)");
  104. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
  105. sizeof(*pax) + 2 + EAP_PAX_MAC_LEN +
  106. EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
  107. if (req == NULL) {
  108. wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
  109. "request");
  110. data->state = FAILURE;
  111. return NULL;
  112. }
  113. pax = wpabuf_put(req, sizeof(*pax));
  114. pax->op_code = EAP_PAX_OP_STD_3;
  115. pax->flags = 0;
  116. pax->mac_id = data->mac_id;
  117. pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
  118. pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
  119. wpabuf_put_be16(req, EAP_PAX_MAC_LEN);
  120. pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
  121. eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
  122. data->rand.r.y, EAP_PAX_RAND_LEN,
  123. (u8 *) data->cid, data->cid_len, NULL, 0, pos);
  124. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
  125. pos, EAP_PAX_MAC_LEN);
  126. pos += EAP_PAX_MAC_LEN;
  127. /* Optional ADE could be added here, if needed */
  128. pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
  129. eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
  130. wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
  131. NULL, 0, NULL, 0, pos);
  132. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
  133. return req;
  134. }
  135. static struct wpabuf * eap_pax_buildReq(struct eap_sm *sm, void *priv, u8 id)
  136. {
  137. struct eap_pax_data *data = priv;
  138. switch (data->state) {
  139. case PAX_STD_1:
  140. return eap_pax_build_std_1(sm, data, id);
  141. case PAX_STD_3:
  142. return eap_pax_build_std_3(sm, data, id);
  143. default:
  144. wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown state %d in buildReq",
  145. data->state);
  146. break;
  147. }
  148. return NULL;
  149. }
  150. static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
  151. struct wpabuf *respData)
  152. {
  153. struct eap_pax_data *data = priv;
  154. struct eap_pax_hdr *resp;
  155. const u8 *pos;
  156. size_t len, mlen;
  157. u8 icvbuf[EAP_PAX_ICV_LEN], *icv;
  158. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
  159. if (pos == NULL || len < sizeof(*resp)) {
  160. wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame");
  161. return TRUE;
  162. }
  163. mlen = sizeof(struct eap_hdr) + 1 + len;
  164. resp = (struct eap_pax_hdr *) pos;
  165. wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
  166. "flags 0x%x mac_id 0x%x dh_group_id 0x%x "
  167. "public_key_id 0x%x",
  168. resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id,
  169. resp->public_key_id);
  170. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
  171. (u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN);
  172. if (data->state == PAX_STD_1 &&
  173. resp->op_code != EAP_PAX_OP_STD_2) {
  174. wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - "
  175. "ignore op %d", resp->op_code);
  176. return TRUE;
  177. }
  178. if (data->state == PAX_STD_3 &&
  179. resp->op_code != EAP_PAX_OP_ACK) {
  180. wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - "
  181. "ignore op %d", resp->op_code);
  182. return TRUE;
  183. }
  184. if (resp->op_code != EAP_PAX_OP_STD_2 &&
  185. resp->op_code != EAP_PAX_OP_ACK) {
  186. wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x",
  187. resp->op_code);
  188. }
  189. if (data->mac_id != resp->mac_id) {
  190. wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, "
  191. "received 0x%x", data->mac_id, resp->mac_id);
  192. return TRUE;
  193. }
  194. if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
  195. wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, "
  196. "received 0x%x", EAP_PAX_DH_GROUP_NONE,
  197. resp->dh_group_id);
  198. return TRUE;
  199. }
  200. if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
  201. wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, "
  202. "received 0x%x", EAP_PAX_PUBLIC_KEY_NONE,
  203. resp->public_key_id);
  204. return TRUE;
  205. }
  206. if (resp->flags & EAP_PAX_FLAGS_MF) {
  207. /* TODO: add support for reassembling fragments */
  208. wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported");
  209. return TRUE;
  210. }
  211. if (resp->flags & EAP_PAX_FLAGS_CE) {
  212. wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag");
  213. return TRUE;
  214. }
  215. if (data->keys_set) {
  216. if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) {
  217. wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet");
  218. return TRUE;
  219. }
  220. icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN;
  221. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
  222. eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
  223. wpabuf_mhead(respData),
  224. wpabuf_len(respData) - EAP_PAX_ICV_LEN,
  225. NULL, 0, NULL, 0, icvbuf);
  226. if (os_memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
  227. wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
  228. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
  229. icvbuf, EAP_PAX_ICV_LEN);
  230. return TRUE;
  231. }
  232. }
  233. return FALSE;
  234. }
  235. static void eap_pax_process_std_2(struct eap_sm *sm,
  236. struct eap_pax_data *data,
  237. struct wpabuf *respData)
  238. {
  239. struct eap_pax_hdr *resp;
  240. u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN];
  241. const u8 *pos;
  242. size_t len, left;
  243. int i;
  244. if (data->state != PAX_STD_1)
  245. return;
  246. wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2");
  247. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
  248. if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN)
  249. return;
  250. resp = (struct eap_pax_hdr *) pos;
  251. pos = (u8 *) (resp + 1);
  252. left = len - sizeof(*resp);
  253. if (left < 2 + EAP_PAX_RAND_LEN ||
  254. WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) {
  255. wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)");
  256. return;
  257. }
  258. pos += 2;
  259. left -= 2;
  260. os_memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN);
  261. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
  262. data->rand.r.y, EAP_PAX_RAND_LEN);
  263. pos += EAP_PAX_RAND_LEN;
  264. left -= EAP_PAX_RAND_LEN;
  265. if (left < 2 || (size_t) 2 + WPA_GET_BE16(pos) > left) {
  266. wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
  267. return;
  268. }
  269. data->cid_len = WPA_GET_BE16(pos);
  270. os_free(data->cid);
  271. data->cid = os_malloc(data->cid_len);
  272. if (data->cid == NULL) {
  273. wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for "
  274. "CID");
  275. return;
  276. }
  277. os_memcpy(data->cid, pos + 2, data->cid_len);
  278. pos += 2 + data->cid_len;
  279. left -= 2 + data->cid_len;
  280. wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
  281. (u8 *) data->cid, data->cid_len);
  282. if (left < 2 + EAP_PAX_MAC_LEN ||
  283. WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
  284. wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)");
  285. return;
  286. }
  287. pos += 2;
  288. left -= 2;
  289. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
  290. pos, EAP_PAX_MAC_LEN);
  291. if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) {
  292. wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID",
  293. (u8 *) data->cid, data->cid_len);
  294. data->state = FAILURE;
  295. return;
  296. }
  297. for (i = 0;
  298. i < EAP_MAX_METHODS &&
  299. (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
  300. sm->user->methods[i].method != EAP_TYPE_NONE);
  301. i++) {
  302. if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
  303. sm->user->methods[i].method == EAP_TYPE_PAX)
  304. break;
  305. }
  306. if (i >= EAP_MAX_METHODS ||
  307. sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
  308. sm->user->methods[i].method != EAP_TYPE_PAX) {
  309. wpa_hexdump_ascii(MSG_DEBUG,
  310. "EAP-PAX: EAP-PAX not enabled for CID",
  311. (u8 *) data->cid, data->cid_len);
  312. data->state = FAILURE;
  313. return;
  314. }
  315. if (sm->user->password == NULL ||
  316. sm->user->password_len != EAP_PAX_AK_LEN) {
  317. wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in "
  318. "user database for CID",
  319. (u8 *) data->cid, data->cid_len);
  320. data->state = FAILURE;
  321. return;
  322. }
  323. os_memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN);
  324. if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
  325. data->rand.e, data->mk, data->ck,
  326. data->ick) < 0) {
  327. wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
  328. "key derivation");
  329. data->state = FAILURE;
  330. return;
  331. }
  332. data->keys_set = 1;
  333. eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
  334. data->rand.r.x, EAP_PAX_RAND_LEN,
  335. data->rand.r.y, EAP_PAX_RAND_LEN,
  336. (u8 *) data->cid, data->cid_len, mac);
  337. if (os_memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) {
  338. wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in "
  339. "PAX_STD-2");
  340. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)",
  341. mac, EAP_PAX_MAC_LEN);
  342. data->state = FAILURE;
  343. return;
  344. }
  345. pos += EAP_PAX_MAC_LEN;
  346. left -= EAP_PAX_MAC_LEN;
  347. if (left < EAP_PAX_ICV_LEN) {
  348. wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in "
  349. "PAX_STD-2", (unsigned long) left);
  350. return;
  351. }
  352. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
  353. eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
  354. wpabuf_head(respData),
  355. wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
  356. icvbuf);
  357. if (os_memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
  358. wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2");
  359. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
  360. icvbuf, EAP_PAX_ICV_LEN);
  361. return;
  362. }
  363. pos += EAP_PAX_ICV_LEN;
  364. left -= EAP_PAX_ICV_LEN;
  365. if (left > 0) {
  366. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
  367. pos, left);
  368. }
  369. data->state = PAX_STD_3;
  370. }
  371. static void eap_pax_process_ack(struct eap_sm *sm,
  372. struct eap_pax_data *data,
  373. struct wpabuf *respData)
  374. {
  375. if (data->state != PAX_STD_3)
  376. return;
  377. wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX-ACK - authentication "
  378. "completed successfully");
  379. data->state = SUCCESS;
  380. }
  381. static void eap_pax_process(struct eap_sm *sm, void *priv,
  382. struct wpabuf *respData)
  383. {
  384. struct eap_pax_data *data = priv;
  385. struct eap_pax_hdr *resp;
  386. const u8 *pos;
  387. size_t len;
  388. if (sm->user == NULL || sm->user->password == NULL) {
  389. wpa_printf(MSG_INFO, "EAP-PAX: Plaintext password not "
  390. "configured");
  391. data->state = FAILURE;
  392. return;
  393. }
  394. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
  395. if (pos == NULL || len < sizeof(*resp))
  396. return;
  397. resp = (struct eap_pax_hdr *) pos;
  398. switch (resp->op_code) {
  399. case EAP_PAX_OP_STD_2:
  400. eap_pax_process_std_2(sm, data, respData);
  401. break;
  402. case EAP_PAX_OP_ACK:
  403. eap_pax_process_ack(sm, data, respData);
  404. break;
  405. }
  406. }
  407. static Boolean eap_pax_isDone(struct eap_sm *sm, void *priv)
  408. {
  409. struct eap_pax_data *data = priv;
  410. return data->state == SUCCESS || data->state == FAILURE;
  411. }
  412. static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
  413. {
  414. struct eap_pax_data *data = priv;
  415. u8 *key;
  416. if (data->state != SUCCESS)
  417. return NULL;
  418. key = os_malloc(EAP_MSK_LEN);
  419. if (key == NULL)
  420. return NULL;
  421. *len = EAP_MSK_LEN;
  422. eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
  423. "Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN,
  424. EAP_MSK_LEN, key);
  425. return key;
  426. }
  427. static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
  428. {
  429. struct eap_pax_data *data = priv;
  430. u8 *key;
  431. if (data->state != SUCCESS)
  432. return NULL;
  433. key = os_malloc(EAP_EMSK_LEN);
  434. if (key == NULL)
  435. return NULL;
  436. *len = EAP_EMSK_LEN;
  437. eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
  438. "Extended Master Session Key",
  439. data->rand.e, 2 * EAP_PAX_RAND_LEN,
  440. EAP_EMSK_LEN, key);
  441. return key;
  442. }
  443. static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
  444. {
  445. struct eap_pax_data *data = priv;
  446. return data->state == SUCCESS;
  447. }
  448. int eap_server_pax_register(void)
  449. {
  450. struct eap_method *eap;
  451. int ret;
  452. eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
  453. EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
  454. if (eap == NULL)
  455. return -1;
  456. eap->init = eap_pax_init;
  457. eap->reset = eap_pax_reset;
  458. eap->buildReq = eap_pax_buildReq;
  459. eap->check = eap_pax_check;
  460. eap->process = eap_pax_process;
  461. eap->isDone = eap_pax_isDone;
  462. eap->getKey = eap_pax_getKey;
  463. eap->isSuccess = eap_pax_isSuccess;
  464. eap->get_emsk = eap_pax_get_emsk;
  465. ret = eap_server_method_register(eap);
  466. if (ret)
  467. eap_server_method_free(eap);
  468. return ret;
  469. }