eap_tnc.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /*
  2. * EAP peer method: EAP-TNC (Trusted Network Connect)
  3. * Copyright (c) 2007, 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 "base64.h"
  17. #include "eap_i.h"
  18. #include "tncc.h"
  19. struct eap_tnc_data {
  20. enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
  21. struct tncc_data *tncc;
  22. struct wpabuf *in_buf;
  23. struct wpabuf *out_buf;
  24. size_t out_used;
  25. size_t fragment_size;
  26. };
  27. /* EAP-TNC Flags */
  28. #define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
  29. #define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
  30. #define EAP_TNC_FLAGS_START 0x20
  31. #define EAP_TNC_VERSION_MASK 0x07
  32. #define EAP_TNC_VERSION 1
  33. static void * eap_tnc_init(struct eap_sm *sm)
  34. {
  35. struct eap_tnc_data *data;
  36. data = os_zalloc(sizeof(*data));
  37. if (data == NULL)
  38. return NULL;
  39. data->state = WAIT_START;
  40. data->fragment_size = 1300;
  41. data->tncc = tncc_init();
  42. if (data->tncc == NULL) {
  43. os_free(data);
  44. return NULL;
  45. }
  46. return data;
  47. }
  48. static void eap_tnc_deinit(struct eap_sm *sm, void *priv)
  49. {
  50. struct eap_tnc_data *data = priv;
  51. wpabuf_free(data->in_buf);
  52. wpabuf_free(data->out_buf);
  53. tncc_deinit(data->tncc);
  54. os_free(data);
  55. }
  56. static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
  57. {
  58. struct wpabuf *msg;
  59. msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id);
  60. if (msg == NULL) {
  61. wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
  62. "for fragment ack");
  63. return NULL;
  64. }
  65. wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */
  66. wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
  67. return msg;
  68. }
  69. static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
  70. struct eap_method_ret *ret, u8 id)
  71. {
  72. struct wpabuf *resp;
  73. u8 flags;
  74. size_t send_len, plen;
  75. ret->ignore = FALSE;
  76. wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
  77. ret->allowNotifications = TRUE;
  78. flags = EAP_TNC_VERSION;
  79. send_len = wpabuf_len(data->out_buf) - data->out_used;
  80. if (1 + send_len > data->fragment_size) {
  81. send_len = data->fragment_size - 1;
  82. flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
  83. if (data->out_used == 0) {
  84. flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
  85. send_len -= 4;
  86. }
  87. }
  88. plen = 1 + send_len;
  89. if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
  90. plen += 4;
  91. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
  92. EAP_CODE_RESPONSE, id);
  93. if (resp == NULL)
  94. return NULL;
  95. wpabuf_put_u8(resp, flags); /* Flags */
  96. if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
  97. wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
  98. wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
  99. send_len);
  100. data->out_used += send_len;
  101. ret->methodState = METHOD_MAY_CONT;
  102. ret->decision = DECISION_FAIL;
  103. if (data->out_used == wpabuf_len(data->out_buf)) {
  104. wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
  105. "(message sent completely)",
  106. (unsigned long) send_len);
  107. wpabuf_free(data->out_buf);
  108. data->out_buf = NULL;
  109. data->out_used = 0;
  110. } else {
  111. wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
  112. "(%lu more to send)", (unsigned long) send_len,
  113. (unsigned long) wpabuf_len(data->out_buf) -
  114. data->out_used);
  115. data->state = WAIT_FRAG_ACK;
  116. }
  117. return resp;
  118. }
  119. static int eap_tnc_process_cont(struct eap_tnc_data *data,
  120. const u8 *buf, size_t len)
  121. {
  122. /* Process continuation of a pending message */
  123. if (len > wpabuf_tailroom(data->in_buf)) {
  124. wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
  125. data->state = FAIL;
  126. return -1;
  127. }
  128. wpabuf_put_data(data->in_buf, buf, len);
  129. wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for "
  130. "%lu bytes more", (unsigned long) len,
  131. (unsigned long) wpabuf_tailroom(data->in_buf));
  132. return 0;
  133. }
  134. static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
  135. struct eap_method_ret *ret,
  136. u8 id, u8 flags,
  137. u32 message_length,
  138. const u8 *buf, size_t len)
  139. {
  140. /* Process a fragment that is not the last one of the message */
  141. if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
  142. wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
  143. "fragmented packet");
  144. ret->ignore = TRUE;
  145. return NULL;
  146. }
  147. if (data->in_buf == NULL) {
  148. /* First fragment of the message */
  149. data->in_buf = wpabuf_alloc(message_length);
  150. if (data->in_buf == NULL) {
  151. wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
  152. "message");
  153. ret->ignore = TRUE;
  154. return NULL;
  155. }
  156. wpabuf_put_data(data->in_buf, buf, len);
  157. wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
  158. "fragment, waiting for %lu bytes more",
  159. (unsigned long) len,
  160. (unsigned long) wpabuf_tailroom(data->in_buf));
  161. }
  162. return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE);
  163. }
  164. static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
  165. struct eap_method_ret *ret,
  166. const struct wpabuf *reqData)
  167. {
  168. struct eap_tnc_data *data = priv;
  169. struct wpabuf *resp;
  170. const u8 *pos, *end;
  171. u8 *rpos, *rpos1;
  172. size_t len, rlen;
  173. size_t imc_len;
  174. char *start_buf, *end_buf;
  175. size_t start_len, end_len;
  176. int tncs_done = 0;
  177. u8 flags, id;
  178. u32 message_length = 0;
  179. struct wpabuf tmpbuf;
  180. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
  181. if (pos == NULL) {
  182. wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
  183. pos, (unsigned long) len);
  184. ret->ignore = TRUE;
  185. return NULL;
  186. }
  187. id = eap_get_id(reqData);
  188. end = pos + len;
  189. if (len == 0)
  190. flags = 0; /* fragment ack */
  191. else
  192. flags = *pos++;
  193. if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
  194. wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
  195. flags & EAP_TNC_VERSION_MASK);
  196. ret->ignore = TRUE;
  197. return NULL;
  198. }
  199. if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
  200. if (end - pos < 4) {
  201. wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
  202. ret->ignore = TRUE;
  203. return NULL;
  204. }
  205. message_length = WPA_GET_BE32(pos);
  206. pos += 4;
  207. if (message_length < (u32) (end - pos)) {
  208. wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
  209. "Length (%d; %ld remaining in this msg)",
  210. message_length, (long) (end - pos));
  211. ret->ignore = TRUE;
  212. return NULL;
  213. }
  214. }
  215. wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
  216. "Message Length %u", flags, message_length);
  217. if (data->state == WAIT_FRAG_ACK) {
  218. if (len > 1) {
  219. wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
  220. "WAIT_FRAG_ACK state");
  221. ret->ignore = TRUE;
  222. return NULL;
  223. }
  224. wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
  225. data->state = PROC_MSG;
  226. return eap_tnc_build_msg(data, ret, id);
  227. }
  228. if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
  229. ret->ignore = TRUE;
  230. return NULL;
  231. }
  232. if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
  233. return eap_tnc_process_fragment(data, ret, id, flags,
  234. message_length, pos,
  235. end - pos);
  236. }
  237. if (data->in_buf == NULL) {
  238. /* Wrap unfragmented messages as wpabuf without extra copy */
  239. wpabuf_set(&tmpbuf, pos, end - pos);
  240. data->in_buf = &tmpbuf;
  241. }
  242. if (data->state == WAIT_START) {
  243. if (!(flags & EAP_TNC_FLAGS_START)) {
  244. wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
  245. "start flag in the first message");
  246. ret->ignore = TRUE;
  247. goto fail;
  248. }
  249. tncc_init_connection(data->tncc);
  250. data->state = PROC_MSG;
  251. } else {
  252. enum tncc_process_res res;
  253. if (flags & EAP_TNC_FLAGS_START) {
  254. wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
  255. "flag again");
  256. ret->ignore = TRUE;
  257. goto fail;
  258. }
  259. res = tncc_process_if_tnccs(data->tncc,
  260. wpabuf_head(data->in_buf),
  261. wpabuf_len(data->in_buf));
  262. switch (res) {
  263. case TNCCS_PROCESS_ERROR:
  264. ret->ignore = TRUE;
  265. goto fail;
  266. case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
  267. case TNCCS_RECOMMENDATION_ERROR:
  268. wpa_printf(MSG_DEBUG, "EAP-TNC: No "
  269. "TNCCS-Recommendation received");
  270. break;
  271. case TNCCS_RECOMMENDATION_ALLOW:
  272. wpa_msg(sm->msg_ctx, MSG_INFO,
  273. "TNC: Recommendation = allow");
  274. tncs_done = 1;
  275. break;
  276. case TNCCS_RECOMMENDATION_NONE:
  277. wpa_msg(sm->msg_ctx, MSG_INFO,
  278. "TNC: Recommendation = none");
  279. tncs_done = 1;
  280. break;
  281. case TNCCS_RECOMMENDATION_ISOLATE:
  282. wpa_msg(sm->msg_ctx, MSG_INFO,
  283. "TNC: Recommendation = isolate");
  284. tncs_done = 1;
  285. break;
  286. }
  287. }
  288. if (data->in_buf != &tmpbuf)
  289. wpabuf_free(data->in_buf);
  290. data->in_buf = NULL;
  291. ret->ignore = FALSE;
  292. ret->methodState = METHOD_MAY_CONT;
  293. ret->decision = DECISION_UNCOND_SUCC;
  294. ret->allowNotifications = TRUE;
  295. if (data->out_buf) {
  296. data->state = PROC_MSG;
  297. return eap_tnc_build_msg(data, ret, id);
  298. }
  299. if (tncs_done) {
  300. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
  301. EAP_CODE_RESPONSE, eap_get_id(reqData));
  302. if (resp == NULL)
  303. return NULL;
  304. wpabuf_put_u8(resp, EAP_TNC_VERSION);
  305. wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an "
  306. "empty ACK message");
  307. return resp;
  308. }
  309. imc_len = tncc_total_send_len(data->tncc);
  310. start_buf = tncc_if_tnccs_start(data->tncc);
  311. if (start_buf == NULL)
  312. return NULL;
  313. start_len = os_strlen(start_buf);
  314. end_buf = tncc_if_tnccs_end();
  315. if (end_buf == NULL) {
  316. os_free(start_buf);
  317. return NULL;
  318. }
  319. end_len = os_strlen(end_buf);
  320. rlen = start_len + imc_len + end_len;
  321. resp = wpabuf_alloc(rlen);
  322. if (resp == NULL) {
  323. os_free(start_buf);
  324. os_free(end_buf);
  325. return NULL;
  326. }
  327. wpabuf_put_data(resp, start_buf, start_len);
  328. os_free(start_buf);
  329. rpos1 = wpabuf_put(resp, 0);
  330. rpos = tncc_copy_send_buf(data->tncc, rpos1);
  331. wpabuf_put(resp, rpos - rpos1);
  332. wpabuf_put_data(resp, end_buf, end_len);
  333. os_free(end_buf);
  334. wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response",
  335. wpabuf_head(resp), wpabuf_len(resp));
  336. data->out_buf = resp;
  337. data->state = PROC_MSG;
  338. return eap_tnc_build_msg(data, ret, id);
  339. fail:
  340. if (data->in_buf == &tmpbuf)
  341. data->in_buf = NULL;
  342. return NULL;
  343. }
  344. int eap_peer_tnc_register(void)
  345. {
  346. struct eap_method *eap;
  347. int ret;
  348. eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
  349. EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
  350. if (eap == NULL)
  351. return -1;
  352. eap->init = eap_tnc_init;
  353. eap->deinit = eap_tnc_deinit;
  354. eap->process = eap_tnc_process;
  355. ret = eap_peer_method_register(eap);
  356. if (ret)
  357. eap_peer_method_free(eap);
  358. return ret;
  359. }