eap_sake.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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. const struct wpabuf *reqData,
  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, eap_get_id(reqData),
  138. 2 + data->peerid_len,
  139. EAP_SAKE_SUBTYPE_IDENTITY);
  140. if (resp == NULL)
  141. return NULL;
  142. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
  143. eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
  144. data->peerid, data->peerid_len);
  145. eap_sake_state(data, CHALLENGE);
  146. return resp;
  147. }
  148. static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
  149. struct eap_sake_data *data,
  150. struct eap_method_ret *ret,
  151. const struct wpabuf *reqData,
  152. const u8 *payload,
  153. size_t payload_len)
  154. {
  155. struct eap_sake_parse_attr attr;
  156. struct wpabuf *resp;
  157. u8 *rpos;
  158. size_t rlen;
  159. if (data->state != IDENTITY && data->state != CHALLENGE) {
  160. wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
  161. "in unexpected state (%d)", data->state);
  162. ret->ignore = TRUE;
  163. return NULL;
  164. }
  165. if (data->state == IDENTITY)
  166. eap_sake_state(data, CHALLENGE);
  167. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
  168. if (eap_sake_parse_attributes(payload, payload_len, &attr))
  169. return NULL;
  170. if (!attr.rand_s) {
  171. wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
  172. "include AT_RAND_S");
  173. return NULL;
  174. }
  175. os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
  176. wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
  177. data->rand_s, EAP_SAKE_RAND_LEN);
  178. if (random_get_bytes(data->rand_p, EAP_SAKE_RAND_LEN)) {
  179. wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
  180. return NULL;
  181. }
  182. wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
  183. data->rand_p, EAP_SAKE_RAND_LEN);
  184. os_free(data->serverid);
  185. data->serverid = NULL;
  186. data->serverid_len = 0;
  187. if (attr.serverid) {
  188. wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
  189. attr.serverid, attr.serverid_len);
  190. data->serverid = os_malloc(attr.serverid_len);
  191. if (data->serverid == NULL)
  192. return NULL;
  193. os_memcpy(data->serverid, attr.serverid, attr.serverid_len);
  194. data->serverid_len = attr.serverid_len;
  195. }
  196. eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
  197. data->rand_s, data->rand_p,
  198. (u8 *) &data->tek, data->msk, data->emsk);
  199. wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
  200. rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
  201. if (data->peerid)
  202. rlen += 2 + data->peerid_len;
  203. resp = eap_sake_build_msg(data, eap_get_id(reqData), rlen,
  204. EAP_SAKE_SUBTYPE_CHALLENGE);
  205. if (resp == NULL)
  206. return NULL;
  207. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
  208. eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P,
  209. data->rand_p, EAP_SAKE_RAND_LEN);
  210. if (data->peerid) {
  211. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
  212. eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
  213. data->peerid, data->peerid_len);
  214. }
  215. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
  216. wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
  217. wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
  218. rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
  219. if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
  220. data->serverid, data->serverid_len,
  221. data->peerid, data->peerid_len, 1,
  222. wpabuf_head(resp), wpabuf_len(resp), rpos,
  223. rpos)) {
  224. wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
  225. wpabuf_free(resp);
  226. return NULL;
  227. }
  228. eap_sake_state(data, CONFIRM);
  229. return resp;
  230. }
  231. static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
  232. struct eap_sake_data *data,
  233. struct eap_method_ret *ret,
  234. const struct wpabuf *reqData,
  235. const u8 *payload,
  236. size_t payload_len)
  237. {
  238. struct eap_sake_parse_attr attr;
  239. u8 mic_s[EAP_SAKE_MIC_LEN];
  240. struct wpabuf *resp;
  241. u8 *rpos;
  242. if (data->state != CONFIRM) {
  243. ret->ignore = TRUE;
  244. return NULL;
  245. }
  246. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
  247. if (eap_sake_parse_attributes(payload, payload_len, &attr))
  248. return NULL;
  249. if (!attr.mic_s) {
  250. wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
  251. "include AT_MIC_S");
  252. return NULL;
  253. }
  254. eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
  255. data->serverid, data->serverid_len,
  256. data->peerid, data->peerid_len, 0,
  257. wpabuf_head(reqData), wpabuf_len(reqData),
  258. attr.mic_s, mic_s);
  259. if (os_memcmp_const(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
  260. wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
  261. eap_sake_state(data, FAILURE);
  262. ret->methodState = METHOD_DONE;
  263. ret->decision = DECISION_FAIL;
  264. ret->allowNotifications = FALSE;
  265. wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
  266. "Response/Auth-Reject");
  267. return eap_sake_build_msg(data, eap_get_id(reqData), 0,
  268. EAP_SAKE_SUBTYPE_AUTH_REJECT);
  269. }
  270. wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
  271. resp = eap_sake_build_msg(data, eap_get_id(reqData),
  272. 2 + EAP_SAKE_MIC_LEN,
  273. EAP_SAKE_SUBTYPE_CONFIRM);
  274. if (resp == NULL)
  275. return NULL;
  276. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
  277. wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
  278. wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
  279. rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
  280. if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
  281. data->serverid, data->serverid_len,
  282. data->peerid, data->peerid_len, 1,
  283. wpabuf_head(resp), wpabuf_len(resp), rpos,
  284. rpos)) {
  285. wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
  286. wpabuf_free(resp);
  287. return NULL;
  288. }
  289. eap_sake_state(data, SUCCESS);
  290. ret->methodState = METHOD_DONE;
  291. ret->decision = DECISION_UNCOND_SUCC;
  292. ret->allowNotifications = FALSE;
  293. return resp;
  294. }
  295. static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
  296. struct eap_method_ret *ret,
  297. const struct wpabuf *reqData)
  298. {
  299. struct eap_sake_data *data = priv;
  300. const struct eap_sake_hdr *req;
  301. struct wpabuf *resp;
  302. const u8 *pos, *end;
  303. size_t len;
  304. u8 subtype, session_id;
  305. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len);
  306. if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
  307. ret->ignore = TRUE;
  308. return NULL;
  309. }
  310. req = (const struct eap_sake_hdr *) pos;
  311. end = pos + len;
  312. subtype = req->subtype;
  313. session_id = req->session_id;
  314. pos = (const u8 *) (req + 1);
  315. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
  316. "session_id %d", subtype, session_id);
  317. wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
  318. pos, end - pos);
  319. if (data->session_id_set && data->session_id != session_id) {
  320. wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
  321. session_id, data->session_id);
  322. ret->ignore = TRUE;
  323. return NULL;
  324. }
  325. data->session_id = session_id;
  326. data->session_id_set = 1;
  327. ret->ignore = FALSE;
  328. ret->methodState = METHOD_MAY_CONT;
  329. ret->decision = DECISION_FAIL;
  330. ret->allowNotifications = TRUE;
  331. switch (subtype) {
  332. case EAP_SAKE_SUBTYPE_IDENTITY:
  333. resp = eap_sake_process_identity(sm, data, ret, reqData,
  334. pos, end - pos);
  335. break;
  336. case EAP_SAKE_SUBTYPE_CHALLENGE:
  337. resp = eap_sake_process_challenge(sm, data, ret, reqData,
  338. pos, end - pos);
  339. break;
  340. case EAP_SAKE_SUBTYPE_CONFIRM:
  341. resp = eap_sake_process_confirm(sm, data, ret, reqData,
  342. pos, end - pos);
  343. break;
  344. default:
  345. wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
  346. "unknown subtype %d", subtype);
  347. ret->ignore = TRUE;
  348. return NULL;
  349. }
  350. if (ret->methodState == METHOD_DONE)
  351. ret->allowNotifications = FALSE;
  352. return resp;
  353. }
  354. static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
  355. {
  356. struct eap_sake_data *data = priv;
  357. return data->state == SUCCESS;
  358. }
  359. static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
  360. {
  361. struct eap_sake_data *data = priv;
  362. u8 *key;
  363. if (data->state != SUCCESS)
  364. return NULL;
  365. key = os_malloc(EAP_MSK_LEN);
  366. if (key == NULL)
  367. return NULL;
  368. os_memcpy(key, data->msk, EAP_MSK_LEN);
  369. *len = EAP_MSK_LEN;
  370. return key;
  371. }
  372. static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
  373. {
  374. struct eap_sake_data *data = priv;
  375. u8 *id;
  376. if (data->state != SUCCESS)
  377. return NULL;
  378. *len = 1 + 2 * EAP_SAKE_RAND_LEN;
  379. id = os_malloc(*len);
  380. if (id == NULL)
  381. return NULL;
  382. id[0] = EAP_TYPE_SAKE;
  383. os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
  384. os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
  385. wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
  386. return id;
  387. }
  388. static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
  389. {
  390. struct eap_sake_data *data = priv;
  391. u8 *key;
  392. if (data->state != SUCCESS)
  393. return NULL;
  394. key = os_malloc(EAP_EMSK_LEN);
  395. if (key == NULL)
  396. return NULL;
  397. os_memcpy(key, data->emsk, EAP_EMSK_LEN);
  398. *len = EAP_EMSK_LEN;
  399. return key;
  400. }
  401. int eap_peer_sake_register(void)
  402. {
  403. struct eap_method *eap;
  404. int ret;
  405. eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
  406. EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
  407. if (eap == NULL)
  408. return -1;
  409. eap->init = eap_sake_init;
  410. eap->deinit = eap_sake_deinit;
  411. eap->process = eap_sake_process;
  412. eap->isKeyAvailable = eap_sake_isKeyAvailable;
  413. eap->getKey = eap_sake_getKey;
  414. eap->getSessionId = eap_sake_get_session_id;
  415. eap->get_emsk = eap_sake_get_emsk;
  416. ret = eap_peer_method_register(eap);
  417. if (ret)
  418. eap_peer_method_free(eap);
  419. return ret;
  420. }