eap_sake.c 13 KB

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