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