eap_sake.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /*
  2. * EAP peer method: EAP-SAKE (RFC 4763)
  3. * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #include "eap_peer/eap_i.h"
  17. #include "eap_common/eap_sake_common.h"
  18. struct eap_sake_data {
  19. enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
  20. u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN];
  21. u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN];
  22. u8 rand_s[EAP_SAKE_RAND_LEN];
  23. u8 rand_p[EAP_SAKE_RAND_LEN];
  24. struct {
  25. u8 auth[EAP_SAKE_TEK_AUTH_LEN];
  26. u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
  27. } tek;
  28. u8 msk[EAP_MSK_LEN];
  29. u8 emsk[EAP_EMSK_LEN];
  30. u8 session_id;
  31. int session_id_set;
  32. u8 *peerid;
  33. size_t peerid_len;
  34. u8 *serverid;
  35. size_t serverid_len;
  36. };
  37. static const char * eap_sake_state_txt(int state)
  38. {
  39. switch (state) {
  40. case IDENTITY:
  41. return "IDENTITY";
  42. case CHALLENGE:
  43. return "CHALLENGE";
  44. case CONFIRM:
  45. return "CONFIRM";
  46. case SUCCESS:
  47. return "SUCCESS";
  48. case FAILURE:
  49. return "FAILURE";
  50. default:
  51. return "?";
  52. }
  53. }
  54. static void eap_sake_state(struct eap_sake_data *data, int state)
  55. {
  56. wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
  57. eap_sake_state_txt(data->state),
  58. eap_sake_state_txt(state));
  59. data->state = state;
  60. }
  61. static void eap_sake_deinit(struct eap_sm *sm, void *priv);
  62. static void * eap_sake_init(struct eap_sm *sm)
  63. {
  64. struct eap_sake_data *data;
  65. const u8 *identity, *password;
  66. size_t identity_len, password_len;
  67. password = eap_get_config_password(sm, &password_len);
  68. if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
  69. wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length "
  70. "configured");
  71. return NULL;
  72. }
  73. data = os_zalloc(sizeof(*data));
  74. if (data == NULL)
  75. return NULL;
  76. data->state = IDENTITY;
  77. identity = eap_get_config_identity(sm, &identity_len);
  78. if (identity) {
  79. data->peerid = os_malloc(identity_len);
  80. if (data->peerid == NULL) {
  81. eap_sake_deinit(sm, data);
  82. return NULL;
  83. }
  84. os_memcpy(data->peerid, identity, identity_len);
  85. data->peerid_len = identity_len;
  86. }
  87. os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN);
  88. os_memcpy(data->root_secret_b,
  89. password + EAP_SAKE_ROOT_SECRET_LEN,
  90. EAP_SAKE_ROOT_SECRET_LEN);
  91. return data;
  92. }
  93. static void eap_sake_deinit(struct eap_sm *sm, void *priv)
  94. {
  95. struct eap_sake_data *data = priv;
  96. os_free(data->serverid);
  97. os_free(data->peerid);
  98. os_free(data);
  99. }
  100. static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
  101. int id, size_t length, u8 subtype)
  102. {
  103. struct eap_sake_hdr *sake;
  104. struct wpabuf *msg;
  105. size_t plen;
  106. plen = length + sizeof(struct eap_sake_hdr);
  107. msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
  108. EAP_CODE_RESPONSE, id);
  109. if (msg == NULL) {
  110. wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
  111. "request");
  112. return NULL;
  113. }
  114. sake = wpabuf_put(msg, sizeof(*sake));
  115. sake->version = EAP_SAKE_VERSION;
  116. sake->session_id = data->session_id;
  117. sake->subtype = subtype;
  118. return msg;
  119. }
  120. static struct wpabuf * eap_sake_process_identity(struct eap_sm *sm,
  121. struct eap_sake_data *data,
  122. struct eap_method_ret *ret,
  123. const struct wpabuf *reqData,
  124. const u8 *payload,
  125. size_t payload_len)
  126. {
  127. struct eap_sake_parse_attr attr;
  128. struct wpabuf *resp;
  129. if (data->state != IDENTITY) {
  130. ret->ignore = TRUE;
  131. return NULL;
  132. }
  133. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
  134. if (eap_sake_parse_attributes(payload, payload_len, &attr))
  135. return NULL;
  136. if (!attr.perm_id_req && !attr.any_id_req) {
  137. wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or "
  138. "AT_ANY_ID_REQ in Request/Identity");
  139. return NULL;
  140. }
  141. wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity");
  142. resp = eap_sake_build_msg(data, eap_get_id(reqData),
  143. 2 + data->peerid_len,
  144. EAP_SAKE_SUBTYPE_IDENTITY);
  145. if (resp == NULL)
  146. return NULL;
  147. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
  148. eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
  149. data->peerid, data->peerid_len);
  150. eap_sake_state(data, CHALLENGE);
  151. return resp;
  152. }
  153. static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
  154. struct eap_sake_data *data,
  155. struct eap_method_ret *ret,
  156. const struct wpabuf *reqData,
  157. const u8 *payload,
  158. size_t payload_len)
  159. {
  160. struct eap_sake_parse_attr attr;
  161. struct wpabuf *resp;
  162. u8 *rpos;
  163. size_t rlen;
  164. if (data->state != IDENTITY && data->state != CHALLENGE) {
  165. wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
  166. "in unexpected state (%d)", data->state);
  167. ret->ignore = TRUE;
  168. return NULL;
  169. }
  170. if (data->state == IDENTITY)
  171. eap_sake_state(data, CHALLENGE);
  172. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
  173. if (eap_sake_parse_attributes(payload, payload_len, &attr))
  174. return NULL;
  175. if (!attr.rand_s) {
  176. wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
  177. "include AT_RAND_S");
  178. return NULL;
  179. }
  180. os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
  181. wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
  182. data->rand_s, EAP_SAKE_RAND_LEN);
  183. if (os_get_random(data->rand_p, EAP_SAKE_RAND_LEN)) {
  184. wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
  185. return NULL;
  186. }
  187. wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
  188. data->rand_p, EAP_SAKE_RAND_LEN);
  189. os_free(data->serverid);
  190. data->serverid = NULL;
  191. data->serverid_len = 0;
  192. if (attr.serverid) {
  193. wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
  194. attr.serverid, attr.serverid_len);
  195. data->serverid = os_malloc(attr.serverid_len);
  196. if (data->serverid == NULL)
  197. return NULL;
  198. os_memcpy(data->serverid, attr.serverid, attr.serverid_len);
  199. data->serverid_len = attr.serverid_len;
  200. }
  201. eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
  202. data->rand_s, data->rand_p,
  203. (u8 *) &data->tek, data->msk, data->emsk);
  204. wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
  205. rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
  206. if (data->peerid)
  207. rlen += 2 + data->peerid_len;
  208. resp = eap_sake_build_msg(data, eap_get_id(reqData), rlen,
  209. EAP_SAKE_SUBTYPE_CHALLENGE);
  210. if (resp == NULL)
  211. return NULL;
  212. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
  213. eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P,
  214. data->rand_p, EAP_SAKE_RAND_LEN);
  215. if (data->peerid) {
  216. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
  217. eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
  218. data->peerid, data->peerid_len);
  219. }
  220. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
  221. wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
  222. wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
  223. rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
  224. if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
  225. data->serverid, data->serverid_len,
  226. data->peerid, data->peerid_len, 1,
  227. wpabuf_head(resp), wpabuf_len(resp), rpos,
  228. rpos)) {
  229. wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
  230. wpabuf_free(resp);
  231. return NULL;
  232. }
  233. eap_sake_state(data, CONFIRM);
  234. return resp;
  235. }
  236. static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
  237. struct eap_sake_data *data,
  238. struct eap_method_ret *ret,
  239. const struct wpabuf *reqData,
  240. const u8 *payload,
  241. size_t payload_len)
  242. {
  243. struct eap_sake_parse_attr attr;
  244. u8 mic_s[EAP_SAKE_MIC_LEN];
  245. struct wpabuf *resp;
  246. u8 *rpos;
  247. if (data->state != CONFIRM) {
  248. ret->ignore = TRUE;
  249. return NULL;
  250. }
  251. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
  252. if (eap_sake_parse_attributes(payload, payload_len, &attr))
  253. return NULL;
  254. if (!attr.mic_s) {
  255. wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
  256. "include AT_MIC_S");
  257. return NULL;
  258. }
  259. eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
  260. data->serverid, data->serverid_len,
  261. data->peerid, data->peerid_len, 0,
  262. wpabuf_head(reqData), wpabuf_len(reqData),
  263. attr.mic_s, mic_s);
  264. if (os_memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
  265. wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
  266. eap_sake_state(data, FAILURE);
  267. ret->methodState = METHOD_DONE;
  268. ret->decision = DECISION_FAIL;
  269. ret->allowNotifications = FALSE;
  270. wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
  271. "Response/Auth-Reject");
  272. return eap_sake_build_msg(data, eap_get_id(reqData), 0,
  273. EAP_SAKE_SUBTYPE_AUTH_REJECT);
  274. }
  275. wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
  276. resp = eap_sake_build_msg(data, eap_get_id(reqData),
  277. 2 + EAP_SAKE_MIC_LEN,
  278. EAP_SAKE_SUBTYPE_CONFIRM);
  279. if (resp == NULL)
  280. return NULL;
  281. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
  282. wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
  283. wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
  284. rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
  285. if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
  286. data->serverid, data->serverid_len,
  287. data->peerid, data->peerid_len, 1,
  288. wpabuf_head(resp), wpabuf_len(resp), rpos,
  289. rpos)) {
  290. wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
  291. wpabuf_free(resp);
  292. return NULL;
  293. }
  294. eap_sake_state(data, SUCCESS);
  295. ret->methodState = METHOD_DONE;
  296. ret->decision = DECISION_UNCOND_SUCC;
  297. ret->allowNotifications = FALSE;
  298. return resp;
  299. }
  300. static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
  301. struct eap_method_ret *ret,
  302. const struct wpabuf *reqData)
  303. {
  304. struct eap_sake_data *data = priv;
  305. const struct eap_sake_hdr *req;
  306. struct wpabuf *resp;
  307. const u8 *pos, *end;
  308. size_t len;
  309. u8 subtype, session_id;
  310. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len);
  311. if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
  312. ret->ignore = TRUE;
  313. return NULL;
  314. }
  315. req = (const struct eap_sake_hdr *) pos;
  316. end = pos + len;
  317. subtype = req->subtype;
  318. session_id = req->session_id;
  319. pos = (const u8 *) (req + 1);
  320. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
  321. "session_id %d", subtype, session_id);
  322. wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
  323. pos, end - pos);
  324. if (data->session_id_set && data->session_id != session_id) {
  325. wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
  326. session_id, data->session_id);
  327. ret->ignore = TRUE;
  328. return NULL;
  329. }
  330. data->session_id = session_id;
  331. data->session_id_set = 1;
  332. ret->ignore = FALSE;
  333. ret->methodState = METHOD_MAY_CONT;
  334. ret->decision = DECISION_FAIL;
  335. ret->allowNotifications = TRUE;
  336. switch (subtype) {
  337. case EAP_SAKE_SUBTYPE_IDENTITY:
  338. resp = eap_sake_process_identity(sm, data, ret, reqData,
  339. pos, end - pos);
  340. break;
  341. case EAP_SAKE_SUBTYPE_CHALLENGE:
  342. resp = eap_sake_process_challenge(sm, data, ret, reqData,
  343. pos, end - pos);
  344. break;
  345. case EAP_SAKE_SUBTYPE_CONFIRM:
  346. resp = eap_sake_process_confirm(sm, data, ret, reqData,
  347. pos, end - pos);
  348. break;
  349. default:
  350. wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
  351. "unknown subtype %d", subtype);
  352. ret->ignore = TRUE;
  353. return NULL;
  354. }
  355. if (ret->methodState == METHOD_DONE)
  356. ret->allowNotifications = FALSE;
  357. return resp;
  358. }
  359. static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
  360. {
  361. struct eap_sake_data *data = priv;
  362. return data->state == SUCCESS;
  363. }
  364. static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
  365. {
  366. struct eap_sake_data *data = priv;
  367. u8 *key;
  368. if (data->state != SUCCESS)
  369. return NULL;
  370. key = os_malloc(EAP_MSK_LEN);
  371. if (key == NULL)
  372. return NULL;
  373. os_memcpy(key, data->msk, EAP_MSK_LEN);
  374. *len = EAP_MSK_LEN;
  375. return key;
  376. }
  377. static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
  378. {
  379. struct eap_sake_data *data = priv;
  380. u8 *key;
  381. if (data->state != SUCCESS)
  382. return NULL;
  383. key = os_malloc(EAP_EMSK_LEN);
  384. if (key == NULL)
  385. return NULL;
  386. os_memcpy(key, data->emsk, EAP_EMSK_LEN);
  387. *len = EAP_EMSK_LEN;
  388. return key;
  389. }
  390. int eap_peer_sake_register(void)
  391. {
  392. struct eap_method *eap;
  393. int ret;
  394. eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
  395. EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
  396. if (eap == NULL)
  397. return -1;
  398. eap->init = eap_sake_init;
  399. eap->deinit = eap_sake_deinit;
  400. eap->process = eap_sake_process;
  401. eap->isKeyAvailable = eap_sake_isKeyAvailable;
  402. eap->getKey = eap_sake_getKey;
  403. eap->get_emsk = eap_sake_get_emsk;
  404. ret = eap_peer_method_register(eap);
  405. if (ret)
  406. eap_peer_method_free(eap);
  407. return ret;
  408. }