eap_server_sake.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /*
  2. * hostapd / EAP-SAKE (RFC 4763) server
  3. * Copyright (c) 2006-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_sake_common.h"
  13. struct eap_sake_data {
  14. enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
  15. u8 rand_s[EAP_SAKE_RAND_LEN];
  16. u8 rand_p[EAP_SAKE_RAND_LEN];
  17. struct {
  18. u8 auth[EAP_SAKE_TEK_AUTH_LEN];
  19. u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
  20. } tek;
  21. u8 msk[EAP_MSK_LEN];
  22. u8 emsk[EAP_EMSK_LEN];
  23. u8 session_id;
  24. u8 *peerid;
  25. size_t peerid_len;
  26. };
  27. static const char * eap_sake_state_txt(int state)
  28. {
  29. switch (state) {
  30. case IDENTITY:
  31. return "IDENTITY";
  32. case CHALLENGE:
  33. return "CHALLENGE";
  34. case CONFIRM:
  35. return "CONFIRM";
  36. case SUCCESS:
  37. return "SUCCESS";
  38. case FAILURE:
  39. return "FAILURE";
  40. default:
  41. return "?";
  42. }
  43. }
  44. static void eap_sake_state(struct eap_sake_data *data, int state)
  45. {
  46. wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
  47. eap_sake_state_txt(data->state),
  48. eap_sake_state_txt(state));
  49. data->state = state;
  50. }
  51. static void * eap_sake_init(struct eap_sm *sm)
  52. {
  53. struct eap_sake_data *data;
  54. data = os_zalloc(sizeof(*data));
  55. if (data == NULL)
  56. return NULL;
  57. data->state = CHALLENGE;
  58. if (os_get_random(&data->session_id, 1)) {
  59. wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
  60. os_free(data);
  61. return NULL;
  62. }
  63. wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
  64. data->session_id);
  65. return data;
  66. }
  67. static void eap_sake_reset(struct eap_sm *sm, void *priv)
  68. {
  69. struct eap_sake_data *data = priv;
  70. os_free(data->peerid);
  71. os_free(data);
  72. }
  73. static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
  74. u8 id, size_t length, u8 subtype)
  75. {
  76. struct eap_sake_hdr *sake;
  77. struct wpabuf *msg;
  78. size_t plen;
  79. plen = sizeof(struct eap_sake_hdr) + length;
  80. msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
  81. EAP_CODE_REQUEST, id);
  82. if (msg == NULL) {
  83. wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
  84. "request");
  85. return NULL;
  86. }
  87. sake = wpabuf_put(msg, sizeof(*sake));
  88. sake->version = EAP_SAKE_VERSION;
  89. sake->session_id = data->session_id;
  90. sake->subtype = subtype;
  91. return msg;
  92. }
  93. static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
  94. struct eap_sake_data *data,
  95. u8 id)
  96. {
  97. struct wpabuf *msg;
  98. size_t plen;
  99. wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
  100. plen = 4;
  101. plen += 2 + sm->server_id_len;
  102. msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
  103. if (msg == NULL) {
  104. data->state = FAILURE;
  105. return NULL;
  106. }
  107. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
  108. eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
  109. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
  110. eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
  111. sm->server_id, sm->server_id_len);
  112. return msg;
  113. }
  114. static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
  115. struct eap_sake_data *data,
  116. u8 id)
  117. {
  118. struct wpabuf *msg;
  119. size_t plen;
  120. wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
  121. if (random_get_bytes(data->rand_s, EAP_SAKE_RAND_LEN)) {
  122. wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
  123. data->state = FAILURE;
  124. return NULL;
  125. }
  126. wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
  127. data->rand_s, EAP_SAKE_RAND_LEN);
  128. plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len;
  129. msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
  130. if (msg == NULL) {
  131. data->state = FAILURE;
  132. return NULL;
  133. }
  134. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
  135. eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
  136. data->rand_s, EAP_SAKE_RAND_LEN);
  137. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
  138. eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
  139. sm->server_id, sm->server_id_len);
  140. return msg;
  141. }
  142. static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
  143. struct eap_sake_data *data,
  144. u8 id)
  145. {
  146. struct wpabuf *msg;
  147. u8 *mic;
  148. wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
  149. msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
  150. EAP_SAKE_SUBTYPE_CONFIRM);
  151. if (msg == NULL) {
  152. data->state = FAILURE;
  153. return NULL;
  154. }
  155. wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
  156. wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S);
  157. wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
  158. mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
  159. if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
  160. sm->server_id, sm->server_id_len,
  161. data->peerid, data->peerid_len, 0,
  162. wpabuf_head(msg), wpabuf_len(msg), mic, mic))
  163. {
  164. wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
  165. data->state = FAILURE;
  166. os_free(msg);
  167. return NULL;
  168. }
  169. return msg;
  170. }
  171. static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
  172. {
  173. struct eap_sake_data *data = priv;
  174. switch (data->state) {
  175. case IDENTITY:
  176. return eap_sake_build_identity(sm, data, id);
  177. case CHALLENGE:
  178. return eap_sake_build_challenge(sm, data, id);
  179. case CONFIRM:
  180. return eap_sake_build_confirm(sm, data, id);
  181. default:
  182. wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
  183. data->state);
  184. break;
  185. }
  186. return NULL;
  187. }
  188. static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
  189. struct wpabuf *respData)
  190. {
  191. struct eap_sake_data *data = priv;
  192. struct eap_sake_hdr *resp;
  193. size_t len;
  194. u8 version, session_id, subtype;
  195. const u8 *pos;
  196. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
  197. if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
  198. wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
  199. return TRUE;
  200. }
  201. resp = (struct eap_sake_hdr *) pos;
  202. version = resp->version;
  203. session_id = resp->session_id;
  204. subtype = resp->subtype;
  205. if (version != EAP_SAKE_VERSION) {
  206. wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
  207. return TRUE;
  208. }
  209. if (session_id != data->session_id) {
  210. wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
  211. session_id, data->session_id);
  212. return TRUE;
  213. }
  214. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
  215. if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
  216. return FALSE;
  217. if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
  218. return FALSE;
  219. if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
  220. return FALSE;
  221. if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
  222. return FALSE;
  223. wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
  224. subtype, data->state);
  225. return TRUE;
  226. }
  227. static void eap_sake_process_identity(struct eap_sm *sm,
  228. struct eap_sake_data *data,
  229. const struct wpabuf *respData,
  230. const u8 *payload, size_t payloadlen)
  231. {
  232. if (data->state != IDENTITY)
  233. return;
  234. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
  235. /* TODO: update identity and select new user data */
  236. eap_sake_state(data, CHALLENGE);
  237. }
  238. static void eap_sake_process_challenge(struct eap_sm *sm,
  239. struct eap_sake_data *data,
  240. const struct wpabuf *respData,
  241. const u8 *payload, size_t payloadlen)
  242. {
  243. struct eap_sake_parse_attr attr;
  244. u8 mic_p[EAP_SAKE_MIC_LEN];
  245. if (data->state != CHALLENGE)
  246. return;
  247. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
  248. if (eap_sake_parse_attributes(payload, payloadlen, &attr))
  249. return;
  250. if (!attr.rand_p || !attr.mic_p) {
  251. wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
  252. "include AT_RAND_P or AT_MIC_P");
  253. return;
  254. }
  255. os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
  256. os_free(data->peerid);
  257. data->peerid = NULL;
  258. data->peerid_len = 0;
  259. if (attr.peerid) {
  260. data->peerid = os_malloc(attr.peerid_len);
  261. if (data->peerid == NULL)
  262. return;
  263. os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
  264. data->peerid_len = attr.peerid_len;
  265. }
  266. if (sm->user == NULL || sm->user->password == NULL ||
  267. sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
  268. wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
  269. "%d-byte key not configured",
  270. 2 * EAP_SAKE_ROOT_SECRET_LEN);
  271. data->state = FAILURE;
  272. return;
  273. }
  274. eap_sake_derive_keys(sm->user->password,
  275. sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
  276. data->rand_s, data->rand_p,
  277. (u8 *) &data->tek, data->msk, data->emsk);
  278. eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
  279. sm->server_id, sm->server_id_len,
  280. data->peerid, data->peerid_len, 1,
  281. wpabuf_head(respData), wpabuf_len(respData),
  282. attr.mic_p, mic_p);
  283. if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
  284. wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
  285. eap_sake_state(data, FAILURE);
  286. return;
  287. }
  288. eap_sake_state(data, CONFIRM);
  289. }
  290. static void eap_sake_process_confirm(struct eap_sm *sm,
  291. struct eap_sake_data *data,
  292. const struct wpabuf *respData,
  293. const u8 *payload, size_t payloadlen)
  294. {
  295. struct eap_sake_parse_attr attr;
  296. u8 mic_p[EAP_SAKE_MIC_LEN];
  297. if (data->state != CONFIRM)
  298. return;
  299. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
  300. if (eap_sake_parse_attributes(payload, payloadlen, &attr))
  301. return;
  302. if (!attr.mic_p) {
  303. wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
  304. "include AT_MIC_P");
  305. return;
  306. }
  307. eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
  308. sm->server_id, sm->server_id_len,
  309. data->peerid, data->peerid_len, 1,
  310. wpabuf_head(respData), wpabuf_len(respData),
  311. attr.mic_p, mic_p);
  312. if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
  313. wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
  314. eap_sake_state(data, FAILURE);
  315. } else
  316. eap_sake_state(data, SUCCESS);
  317. }
  318. static void eap_sake_process_auth_reject(struct eap_sm *sm,
  319. struct eap_sake_data *data,
  320. const struct wpabuf *respData,
  321. const u8 *payload, size_t payloadlen)
  322. {
  323. wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
  324. eap_sake_state(data, FAILURE);
  325. }
  326. static void eap_sake_process(struct eap_sm *sm, void *priv,
  327. struct wpabuf *respData)
  328. {
  329. struct eap_sake_data *data = priv;
  330. struct eap_sake_hdr *resp;
  331. u8 subtype;
  332. size_t len;
  333. const u8 *pos, *end;
  334. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
  335. if (pos == NULL || len < sizeof(struct eap_sake_hdr))
  336. return;
  337. resp = (struct eap_sake_hdr *) pos;
  338. end = pos + len;
  339. subtype = resp->subtype;
  340. pos = (u8 *) (resp + 1);
  341. wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
  342. pos, end - pos);
  343. switch (subtype) {
  344. case EAP_SAKE_SUBTYPE_IDENTITY:
  345. eap_sake_process_identity(sm, data, respData, pos, end - pos);
  346. break;
  347. case EAP_SAKE_SUBTYPE_CHALLENGE:
  348. eap_sake_process_challenge(sm, data, respData, pos, end - pos);
  349. break;
  350. case EAP_SAKE_SUBTYPE_CONFIRM:
  351. eap_sake_process_confirm(sm, data, respData, pos, end - pos);
  352. break;
  353. case EAP_SAKE_SUBTYPE_AUTH_REJECT:
  354. eap_sake_process_auth_reject(sm, data, respData, pos,
  355. end - pos);
  356. break;
  357. }
  358. }
  359. static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
  360. {
  361. struct eap_sake_data *data = priv;
  362. return data->state == SUCCESS || data->state == FAILURE;
  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. static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
  391. {
  392. struct eap_sake_data *data = priv;
  393. return data->state == SUCCESS;
  394. }
  395. int eap_server_sake_register(void)
  396. {
  397. struct eap_method *eap;
  398. int ret;
  399. eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
  400. EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
  401. if (eap == NULL)
  402. return -1;
  403. eap->init = eap_sake_init;
  404. eap->reset = eap_sake_reset;
  405. eap->buildReq = eap_sake_buildReq;
  406. eap->check = eap_sake_check;
  407. eap->process = eap_sake_process;
  408. eap->isDone = eap_sake_isDone;
  409. eap->getKey = eap_sake_getKey;
  410. eap->isSuccess = eap_sake_isSuccess;
  411. eap->get_emsk = eap_sake_get_emsk;
  412. ret = eap_server_method_register(eap);
  413. if (ret)
  414. eap_server_method_free(eap);
  415. return ret;
  416. }