eap_wsc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /*
  2. * EAP-WSC server for Wi-Fi Protected Setup
  3. * Copyright (c) 2007-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_i.h"
  17. #include "eap_common/eap_wsc_common.h"
  18. #include "wps/wps.h"
  19. struct eap_wsc_data {
  20. enum { START, MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
  21. int registrar;
  22. struct wpabuf *in_buf;
  23. struct wpabuf *out_buf;
  24. enum wsc_op_code in_op_code, out_op_code;
  25. size_t out_used;
  26. size_t fragment_size;
  27. struct wps_data *wps;
  28. };
  29. static const char * eap_wsc_state_txt(int state)
  30. {
  31. switch (state) {
  32. case START:
  33. return "START";
  34. case MSG:
  35. return "MSG";
  36. case FRAG_ACK:
  37. return "FRAG_ACK";
  38. case WAIT_FRAG_ACK:
  39. return "WAIT_FRAG_ACK";
  40. case DONE:
  41. return "DONE";
  42. case FAIL:
  43. return "FAIL";
  44. default:
  45. return "?";
  46. }
  47. }
  48. static void eap_wsc_state(struct eap_wsc_data *data, int state)
  49. {
  50. wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
  51. eap_wsc_state_txt(data->state),
  52. eap_wsc_state_txt(state));
  53. data->state = state;
  54. }
  55. static void * eap_wsc_init(struct eap_sm *sm)
  56. {
  57. struct eap_wsc_data *data;
  58. int registrar;
  59. struct wps_config cfg;
  60. if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
  61. os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
  62. 0)
  63. registrar = 0; /* Supplicant is Registrar */
  64. else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
  65. os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
  66. == 0)
  67. registrar = 1; /* Supplicant is Enrollee */
  68. else {
  69. wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
  70. sm->identity, sm->identity_len);
  71. return NULL;
  72. }
  73. data = os_zalloc(sizeof(*data));
  74. if (data == NULL)
  75. return NULL;
  76. data->state = registrar ? START : MSG;
  77. data->registrar = registrar;
  78. os_memset(&cfg, 0, sizeof(cfg));
  79. cfg.wps = sm->wps;
  80. cfg.registrar = registrar;
  81. if (registrar) {
  82. if (sm->wps == NULL || sm->wps->registrar == NULL) {
  83. wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
  84. "initialized");
  85. os_free(data);
  86. return NULL;
  87. }
  88. } else {
  89. if (sm->user == NULL || sm->user->password == NULL) {
  90. wpa_printf(MSG_INFO, "EAP-WSC: No AP PIN (password) "
  91. "configured for Enrollee functionality");
  92. os_free(data);
  93. return NULL;
  94. }
  95. cfg.pin = sm->user->password;
  96. cfg.pin_len = sm->user->password_len;
  97. }
  98. cfg.assoc_wps_ie = sm->assoc_wps_ie;
  99. data->wps = wps_init(&cfg);
  100. if (data->wps == NULL) {
  101. os_free(data);
  102. return NULL;
  103. }
  104. data->fragment_size = WSC_FRAGMENT_SIZE;
  105. return data;
  106. }
  107. static void eap_wsc_reset(struct eap_sm *sm, void *priv)
  108. {
  109. struct eap_wsc_data *data = priv;
  110. wpabuf_free(data->in_buf);
  111. wpabuf_free(data->out_buf);
  112. wps_deinit(data->wps);
  113. os_free(data);
  114. }
  115. static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
  116. struct eap_wsc_data *data, u8 id)
  117. {
  118. struct wpabuf *req;
  119. req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
  120. EAP_CODE_REQUEST, id);
  121. if (req == NULL) {
  122. wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
  123. "request");
  124. return NULL;
  125. }
  126. wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
  127. wpabuf_put_u8(req, WSC_Start); /* Op-Code */
  128. wpabuf_put_u8(req, 0); /* Flags */
  129. return req;
  130. }
  131. static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
  132. {
  133. struct wpabuf *req;
  134. u8 flags;
  135. size_t send_len, plen;
  136. flags = 0;
  137. send_len = wpabuf_len(data->out_buf) - data->out_used;
  138. if (2 + send_len > data->fragment_size) {
  139. send_len = data->fragment_size - 2;
  140. flags |= WSC_FLAGS_MF;
  141. if (data->out_used == 0) {
  142. flags |= WSC_FLAGS_LF;
  143. send_len -= 2;
  144. }
  145. }
  146. plen = 2 + send_len;
  147. if (flags & WSC_FLAGS_LF)
  148. plen += 2;
  149. req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
  150. EAP_CODE_REQUEST, id);
  151. if (req == NULL) {
  152. wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
  153. "request");
  154. return NULL;
  155. }
  156. wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
  157. wpabuf_put_u8(req, flags); /* Flags */
  158. if (flags & WSC_FLAGS_LF)
  159. wpabuf_put_be16(req, wpabuf_len(data->out_buf));
  160. wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
  161. send_len);
  162. data->out_used += send_len;
  163. if (data->out_used == wpabuf_len(data->out_buf)) {
  164. wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
  165. "(message sent completely)",
  166. (unsigned long) send_len);
  167. wpabuf_free(data->out_buf);
  168. data->out_buf = NULL;
  169. data->out_used = 0;
  170. eap_wsc_state(data, MSG);
  171. } else {
  172. wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
  173. "(%lu more to send)", (unsigned long) send_len,
  174. (unsigned long) wpabuf_len(data->out_buf) -
  175. data->out_used);
  176. eap_wsc_state(data, WAIT_FRAG_ACK);
  177. }
  178. return req;
  179. }
  180. static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
  181. {
  182. struct eap_wsc_data *data = priv;
  183. switch (data->state) {
  184. case START:
  185. return eap_wsc_build_start(sm, data, id);
  186. case MSG:
  187. if (data->out_buf == NULL) {
  188. data->out_buf = wps_get_msg(data->wps,
  189. &data->out_op_code);
  190. if (data->out_buf == NULL) {
  191. wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
  192. "receive message from WPS");
  193. return NULL;
  194. }
  195. data->out_used = 0;
  196. }
  197. /* pass through */
  198. case WAIT_FRAG_ACK:
  199. return eap_wsc_build_msg(data, id);
  200. case FRAG_ACK:
  201. return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
  202. default:
  203. wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
  204. "buildReq", data->state);
  205. return NULL;
  206. }
  207. }
  208. static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
  209. struct wpabuf *respData)
  210. {
  211. const u8 *pos;
  212. size_t len;
  213. pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
  214. respData, &len);
  215. if (pos == NULL || len < 2) {
  216. wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
  217. return TRUE;
  218. }
  219. return FALSE;
  220. }
  221. static int eap_wsc_process_cont(struct eap_wsc_data *data,
  222. const u8 *buf, size_t len, u8 op_code)
  223. {
  224. /* Process continuation of a pending message */
  225. if (op_code != data->in_op_code) {
  226. wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
  227. "fragment (expected %d)",
  228. op_code, data->in_op_code);
  229. eap_wsc_state(data, FAIL);
  230. return -1;
  231. }
  232. if (len > wpabuf_tailroom(data->in_buf)) {
  233. wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
  234. eap_wsc_state(data, FAIL);
  235. return -1;
  236. }
  237. wpabuf_put_data(data->in_buf, buf, len);
  238. wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
  239. "bytes more", (unsigned long) len,
  240. (unsigned long) wpabuf_tailroom(data->in_buf));
  241. return 0;
  242. }
  243. static int eap_wsc_process_fragment(struct eap_wsc_data *data,
  244. u8 flags, u8 op_code, u16 message_length,
  245. const u8 *buf, size_t len)
  246. {
  247. /* Process a fragment that is not the last one of the message */
  248. if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
  249. wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length "
  250. "field in a fragmented packet");
  251. return -1;
  252. }
  253. if (data->in_buf == NULL) {
  254. /* First fragment of the message */
  255. data->in_buf = wpabuf_alloc(message_length);
  256. if (data->in_buf == NULL) {
  257. wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
  258. "message");
  259. return -1;
  260. }
  261. data->in_op_code = op_code;
  262. wpabuf_put_data(data->in_buf, buf, len);
  263. wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in "
  264. "first fragment, waiting for %lu bytes more",
  265. (unsigned long) len,
  266. (unsigned long) wpabuf_tailroom(data->in_buf));
  267. }
  268. return 0;
  269. }
  270. static void eap_wsc_process(struct eap_sm *sm, void *priv,
  271. struct wpabuf *respData)
  272. {
  273. struct eap_wsc_data *data = priv;
  274. const u8 *start, *pos, *end;
  275. size_t len;
  276. u8 op_code, flags;
  277. u16 message_length = 0;
  278. enum wps_process_res res;
  279. struct wpabuf tmpbuf;
  280. pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
  281. respData, &len);
  282. if (pos == NULL || len < 2)
  283. return; /* Should not happen; message already verified */
  284. start = pos;
  285. end = start + len;
  286. op_code = *pos++;
  287. flags = *pos++;
  288. if (flags & WSC_FLAGS_LF) {
  289. if (end - pos < 2) {
  290. wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
  291. return;
  292. }
  293. message_length = WPA_GET_BE16(pos);
  294. pos += 2;
  295. if (message_length < end - pos) {
  296. wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
  297. "Length");
  298. return;
  299. }
  300. }
  301. wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
  302. "Flags 0x%x Message Length %d",
  303. op_code, flags, message_length);
  304. if (data->state == WAIT_FRAG_ACK) {
  305. if (op_code != WSC_FRAG_ACK) {
  306. wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
  307. "in WAIT_FRAG_ACK state", op_code);
  308. eap_wsc_state(data, FAIL);
  309. return;
  310. }
  311. wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
  312. eap_wsc_state(data, MSG);
  313. return;
  314. }
  315. if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
  316. op_code != WSC_Done) {
  317. wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
  318. op_code);
  319. eap_wsc_state(data, FAIL);
  320. return;
  321. }
  322. if (data->in_buf &&
  323. eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
  324. eap_wsc_state(data, FAIL);
  325. return;
  326. }
  327. if (flags & WSC_FLAGS_MF) {
  328. if (eap_wsc_process_fragment(data, flags, op_code,
  329. message_length, pos, end - pos) <
  330. 0)
  331. eap_wsc_state(data, FAIL);
  332. else
  333. eap_wsc_state(data, FRAG_ACK);
  334. return;
  335. }
  336. if (data->in_buf == NULL) {
  337. /* Wrap unfragmented messages as wpabuf without extra copy */
  338. wpabuf_set(&tmpbuf, pos, end - pos);
  339. data->in_buf = &tmpbuf;
  340. }
  341. res = wps_process_msg(data->wps, op_code, data->in_buf);
  342. switch (res) {
  343. case WPS_DONE:
  344. wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
  345. "successfully - report EAP failure");
  346. eap_wsc_state(data, FAIL);
  347. break;
  348. case WPS_CONTINUE:
  349. eap_wsc_state(data, MSG);
  350. break;
  351. case WPS_FAILURE:
  352. wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
  353. eap_wsc_state(data, FAIL);
  354. break;
  355. }
  356. if (data->in_buf != &tmpbuf)
  357. wpabuf_free(data->in_buf);
  358. data->in_buf = NULL;
  359. }
  360. static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
  361. {
  362. struct eap_wsc_data *data = priv;
  363. return data->state == FAIL;
  364. }
  365. static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
  366. {
  367. /* EAP-WSC will always result in EAP-Failure */
  368. return FALSE;
  369. }
  370. static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
  371. {
  372. /* Recommended retransmit times: retransmit timeout 5 seconds,
  373. * per-message timeout 15 seconds, i.e., 3 tries. */
  374. sm->MaxRetrans = 2; /* total 3 attempts */
  375. return 5;
  376. }
  377. int eap_server_wsc_register(void)
  378. {
  379. struct eap_method *eap;
  380. int ret;
  381. eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
  382. EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
  383. "WSC");
  384. if (eap == NULL)
  385. return -1;
  386. eap->init = eap_wsc_init;
  387. eap->reset = eap_wsc_reset;
  388. eap->buildReq = eap_wsc_buildReq;
  389. eap->check = eap_wsc_check;
  390. eap->process = eap_wsc_process;
  391. eap->isDone = eap_wsc_isDone;
  392. eap->isSuccess = eap_wsc_isSuccess;
  393. eap->getTimeout = eap_wsc_getTimeout;
  394. ret = eap_server_method_register(eap);
  395. if (ret)
  396. eap_server_method_free(eap);
  397. return ret;
  398. }