18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP server method: EAP-TNC (Trusted Network Connect) 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007-2010, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_i.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "tncs.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eap_tnc_data { 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum eap_tnc_state { 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt START, CONTINUE, RECOMMENDATION, FRAG_ACK, WAIT_FRAG_ACK, DONE, 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt FAIL 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } state; 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum { ALLOW, ISOLATE, NO_ACCESS, NO_RECOMMENDATION } recommendation; 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct tncs_data *tncs; 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *in_buf; 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *out_buf; 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t out_used; 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t fragment_size; 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned int was_done:1; 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned int was_fail:1; 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* EAP-TNC Flags */ 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_TNC_FLAGS_START 0x20 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_TNC_VERSION_MASK 0x07 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_TNC_VERSION 1 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char * eap_tnc_state_txt(enum eap_tnc_state state) 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (state) { 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case START: 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "START"; 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case CONTINUE: 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "CONTINUE"; 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RECOMMENDATION: 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "RECOMMENDATION"; 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case FRAG_ACK: 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "FRAG_ACK"; 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case WAIT_FRAG_ACK: 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "WAIT_FRAG_ACK"; 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case DONE: 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "DONE"; 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case FAIL: 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "FAIL"; 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "??"; 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_tnc_set_state(struct eap_tnc_data *data, 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum eap_tnc_state new_state) 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: %s -> %s", 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_state_txt(data->state), 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_state_txt(new_state)); 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = new_state; 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * eap_tnc_init(struct eap_sm *sm) 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data; 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_zalloc(sizeof(*data)); 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, START); 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->tncs = tncs_init(); 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->tncs == NULL) { 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->fragment_size = sm->fragment_size > 100 ? 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->fragment_size - 98 : 1300; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_tnc_reset(struct eap_sm *sm, void *priv) 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data = priv; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->in_buf); 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->out_buf); 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tncs_deinit(data->tncs); 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_tnc_build_start(struct eap_sm *sm, 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data, u8 id) 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *req; 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_REQUEST, 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt id); 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req == NULL) { 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for " 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "request"); 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION); 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, CONTINUE); 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return req; 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_tnc_build(struct eap_sm *sm, 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data) 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *req; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *rpos, *rpos1; 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t rlen; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *start_buf, *end_buf; 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t start_len, end_len; 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t imv_len; 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt imv_len = tncs_total_send_len(data->tncs); 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt start_buf = tncs_if_tnccs_start(data->tncs); 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (start_buf == NULL) 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt start_len = os_strlen(start_buf); 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end_buf = tncs_if_tnccs_end(); 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end_buf == NULL) { 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(start_buf); 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end_len = os_strlen(end_buf); 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rlen = start_len + imv_len + end_len; 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt req = wpabuf_alloc(rlen); 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req == NULL) { 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(start_buf); 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(end_buf); 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(req, start_buf, start_len); 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(start_buf); 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rpos1 = wpabuf_put(req, 0); 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rpos = tncs_copy_send_buf(data->tncs, rpos1); 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put(req, rpos - rpos1); 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(req, end_buf, end_len); 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(end_buf); 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Request", 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_head(req), wpabuf_len(req)); 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return req; 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm, 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data) 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (data->recommendation) { 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ALLOW: 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, DONE); 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ISOLATE: 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: support assignment to a different VLAN */ 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case NO_ACCESS: 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case NO_RECOMMENDATION: 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, DONE); 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation"); 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_build(sm, data); 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code) 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg; 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id); 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) { 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory " 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "for fragment ack"); 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */ 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack"); 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, u8 id) 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *req; 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 flags; 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t send_len, plen; 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Request"); 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags = EAP_TNC_VERSION; 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len = wpabuf_len(data->out_buf) - data->out_used; 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (1 + send_len > data->fragment_size) { 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len = data->fragment_size - 1; 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS; 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_used == 0) { 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED; 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len -= 4; 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = 1 + send_len; 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen += 4; 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen, 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_CODE_REQUEST, id); 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req == NULL) 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(req, flags); /* Flags */ 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_be32(req, wpabuf_len(data->out_buf)); 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len); 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used += send_len; 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_used == wpabuf_len(data->out_buf)) { 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(message sent completely)", 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) send_len); 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->out_buf); 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_buf = NULL; 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used = 0; 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->was_fail) 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (data->was_done) 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, DONE); 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(%lu more to send)", (unsigned long) send_len, 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(data->out_buf) - 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used); 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state == FAIL) 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->was_fail = 1; 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (data->state == DONE) 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->was_done = 1; 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, WAIT_FRAG_ACK); 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return req; 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id) 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data = priv; 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (data->state) { 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case START: 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tncs_init_connection(data->tncs); 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_build_start(sm, data, id); 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case CONTINUE: 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_buf == NULL) { 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_buf = eap_tnc_build(sm, data); 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_buf == NULL) { 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to " 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "generate message"); 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used = 0; 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_build_msg(data, id); 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case RECOMMENDATION: 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_buf == NULL) { 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_buf = eap_tnc_build_recommendation(sm, data); 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_buf == NULL) { 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to " 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "generate recommendation message"); 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used = 0; 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_build_msg(data, id); 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case WAIT_FRAG_ACK: 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_build_msg(data, id); 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case FRAG_ACK: 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_build_frag_ack(id, EAP_CODE_REQUEST); 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case DONE: 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case FAIL: 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_tnc_check(struct eap_sm *sm, void *priv, 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *respData) 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data = priv; 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos; 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len; 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &len); 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL) { 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame"); 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return TRUE; 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0 && data->state != WAIT_FRAG_ACK) { 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (empty)"); 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return TRUE; 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0) 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return FALSE; /* Fragment ACK does not include flags */ 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) { 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d", 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos & EAP_TNC_VERSION_MASK); 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return TRUE; 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*pos & EAP_TNC_FLAGS_START) { 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag"); 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return TRUE; 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return FALSE; 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void tncs_process(struct eap_tnc_data *data, struct wpabuf *inbuf) 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum tncs_process_res res; 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = tncs_process_if_tnccs(data->tncs, wpabuf_head(inbuf), 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(inbuf)); 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (res) { 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_RECOMMENDATION_ALLOW: 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access"); 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, RECOMMENDATION); 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->recommendation = ALLOW; 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_RECOMMENDATION_NO_RECOMMENDATION: 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation"); 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, RECOMMENDATION); 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->recommendation = NO_RECOMMENDATION; 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_RECOMMENDATION_ISOLATE: 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation"); 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, RECOMMENDATION); 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->recommendation = ISOLATE; 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_RECOMMENDATION_NO_ACCESS: 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access"); 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, RECOMMENDATION); 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->recommendation = NO_ACCESS; 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_PROCESS_ERROR: 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error"); 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_tnc_process_cont(struct eap_tnc_data *data, 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *buf, size_t len) 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Process continuation of a pending message */ 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len > wpabuf_tailroom(data->in_buf)) { 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow"); 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(data->in_buf, buf, len); 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for %lu " 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "bytes more", (unsigned long) len, 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_tailroom(data->in_buf)); 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_tnc_process_fragment(struct eap_tnc_data *data, 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 flags, u32 message_length, 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *buf, size_t len) 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Process a fragment that is not the last one of the message */ 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) { 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a " 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "fragmented packet"); 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL) { 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* First fragment of the message */ 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = wpabuf_alloc(message_length); 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL) { 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for " 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "message"); 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(data->in_buf, buf, len); 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first " 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "fragment, waiting for %lu bytes more", 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) len, 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_tailroom(data->in_buf)); 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_tnc_process(struct eap_sm *sm, void *priv, 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *respData) 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data = priv; 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end; 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len; 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 flags; 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 message_length = 0; 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf tmpbuf; 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len); 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL) 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; /* Should not happen; message already verified */ 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = pos + len; 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 1 && (data->state == DONE || data->state == FAIL)) { 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last " 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "message"); 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0) { 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* fragment ack */ 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags = 0; 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags = *pos++; 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - pos < 4) { 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow"); 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt message_length = WPA_GET_BE32(pos); 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 4; 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 483623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt if (message_length < (u32) (end - pos) || 484623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt message_length > 75000) { 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Length (%d; %ld remaining in this msg)", 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt message_length, (long) (end - pos)); 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x " 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Message Length %u", flags, message_length); 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state == WAIT_FRAG_ACK) { 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len > 1) { 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload " 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "in WAIT_FRAG_ACK state"); 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, CONTINUE); 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap_tnc_process_fragment(data, flags, message_length, 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, end - pos) < 0) 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FAIL); 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, FRAG_ACK); 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (data->state == FRAG_ACK) { 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_tnc_set_state(data, CONTINUE); 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL) { 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Wrap unfragmented messages as wpabuf without extra copy */ 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_set(&tmpbuf, pos, end - pos); 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = &tmpbuf; 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload", 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_head(data->in_buf), wpabuf_len(data->in_buf)); 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tncs_process(data, data->in_buf); 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf != &tmpbuf) 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->in_buf); 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = NULL; 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv) 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data = priv; 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data->state == DONE || data->state == FAIL; 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv) 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data = priv; 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data->state == DONE; 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_server_tnc_register(void) 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method *eap; 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC"); 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap == NULL) 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->init = eap_tnc_init; 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->reset = eap_tnc_reset; 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->buildReq = eap_tnc_buildReq; 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->check = eap_tnc_check; 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->process = eap_tnc_process; 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->isDone = eap_tnc_isDone; 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->isSuccess = eap_tnc_isSuccess; 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = eap_server_method_register(eap); 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_server_method_free(eap); 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 577