18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP peer method: EAP-TNC (Trusted Network Connect) 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007, 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 "tncc.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eap_tnc_data { 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state; 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct tncc_data *tncc; 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *in_buf; 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *out_buf; 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t out_used; 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t fragment_size; 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* EAP-TNC Flags */ 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_TNC_FLAGS_START 0x20 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_TNC_VERSION_MASK 0x07 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EAP_TNC_VERSION 1 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * eap_tnc_init(struct eap_sm *sm) 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data; 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_zalloc(sizeof(*data)); 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = WAIT_START; 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->fragment_size = 1300; 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->tncc = tncc_init(); 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->tncc == NULL) { 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data; 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_tnc_deinit(struct eap_sm *sm, void *priv) 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data = priv; 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->in_buf); 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->out_buf); 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tncc_deinit(data->tncc); 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code) 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg; 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id); 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) { 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory " 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "for fragment ack"); 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */ 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack"); 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method_ret *ret, u8 id) 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *resp; 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 flags; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t send_len, plen; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = FALSE; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response"); 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->allowNotifications = TRUE; 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags = EAP_TNC_VERSION; 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len = wpabuf_len(data->out_buf) - data->out_used; 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (1 + send_len > data->fragment_size) { 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len = data->fragment_size - 1; 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS; 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_used == 0) { 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len -= 4; 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = 1 + send_len; 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen += 4; 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen, 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_CODE_RESPONSE, id); 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (resp == NULL) 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(resp, flags); /* Flags */ 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_be32(resp, wpabuf_len(data->out_buf)); 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len); 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used += send_len; 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->methodState = METHOD_MAY_CONT; 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->decision = DECISION_FAIL; 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_used == wpabuf_len(data->out_buf)) { 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(message sent completely)", 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) send_len); 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->out_buf); 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_buf = NULL; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used = 0; 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(%lu more to send)", (unsigned long) send_len, 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(data->out_buf) - 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used); 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = WAIT_FRAG_ACK; 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return resp; 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_tnc_process_cont(struct eap_tnc_data *data, 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *buf, size_t len) 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Process continuation of a pending message */ 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len > wpabuf_tailroom(data->in_buf)) { 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow"); 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = FAIL; 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(data->in_buf, buf, len); 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for " 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%lu bytes more", (unsigned long) len, 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_tailroom(data->in_buf)); 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data, 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method_ret *ret, 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 id, u8 flags, 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 message_length, 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *buf, size_t len) 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Process a fragment that is not the last one of the message */ 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) { 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a " 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "fragmented packet"); 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL) { 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* First fragment of the message */ 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = wpabuf_alloc(message_length); 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL) { 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for " 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "message"); 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(data->in_buf, buf, len); 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first " 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "fragment, waiting for %lu bytes more", 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) len, 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_tailroom(data->in_buf)); 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE); 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv, 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method_ret *ret, 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct wpabuf *reqData) 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_tnc_data *data = priv; 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *resp; 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end; 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *rpos, *rpos1; 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len, rlen; 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t imc_len; 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *start_buf, *end_buf; 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t start_len, end_len; 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int tncs_done = 0; 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 flags, id; 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 message_length = 0; 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf tmpbuf; 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len); 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL) { 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)", 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, (unsigned long) len); 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt id = eap_get_id(reqData); 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = pos + len; 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0) 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags = 0; /* fragment ack */ 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags = *pos++; 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) { 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d", 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags & EAP_TNC_VERSION_MASK); 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - pos < 4) { 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow"); 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt message_length = WPA_GET_BE32(pos); 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 4; 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (message_length < (u32) (end - pos)) { 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Length (%d; %ld remaining in this msg)", 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt message_length, (long) (end - pos)); 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x " 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Message Length %u", flags, message_length); 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state == WAIT_FRAG_ACK) { 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len > 1) { 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in " 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "WAIT_FRAG_ACK state"); 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = PROC_MSG; 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_build_msg(data, ret, id); 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_process_fragment(data, ret, id, flags, 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt message_length, pos, 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end - pos); 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL) { 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Wrap unfragmented messages as wpabuf without extra copy */ 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_set(&tmpbuf, pos, end - pos); 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = &tmpbuf; 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state == WAIT_START) { 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(flags & EAP_TNC_FLAGS_START)) { 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use " 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "start flag in the first message"); 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tncc_init_connection(data->tncc); 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = PROC_MSG; 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum tncc_process_res res; 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & EAP_TNC_FLAGS_START) { 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start " 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "flag again"); 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = tncc_process_if_tnccs(data->tncc, 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_head(data->in_buf), 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(data->in_buf)); 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (res) { 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_PROCESS_ERROR: 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_PROCESS_OK_NO_RECOMMENDATION: 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_RECOMMENDATION_ERROR: 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: No " 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "TNCCS-Recommendation received"); 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_RECOMMENDATION_ALLOW: 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_msg(sm->msg_ctx, MSG_INFO, 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "TNC: Recommendation = allow"); 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tncs_done = 1; 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_RECOMMENDATION_NONE: 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_msg(sm->msg_ctx, MSG_INFO, 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "TNC: Recommendation = none"); 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tncs_done = 1; 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case TNCCS_RECOMMENDATION_ISOLATE: 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_msg(sm->msg_ctx, MSG_INFO, 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "TNC: Recommendation = isolate"); 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tncs_done = 1; 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf != &tmpbuf) 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->in_buf); 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = NULL; 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = FALSE; 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->methodState = METHOD_MAY_CONT; 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->decision = DECISION_UNCOND_SUCC; 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->allowNotifications = TRUE; 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_buf) { 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = PROC_MSG; 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_build_msg(data, ret, id); 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tncs_done) { 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_CODE_RESPONSE, eap_get_id(reqData)); 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (resp == NULL) 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(resp, EAP_TNC_VERSION); 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an " 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "empty ACK message"); 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return resp; 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt imc_len = tncc_total_send_len(data->tncc); 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt start_buf = tncc_if_tnccs_start(data->tncc); 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (start_buf == NULL) 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt start_len = os_strlen(start_buf); 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end_buf = tncc_if_tnccs_end(); 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end_buf == NULL) { 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(start_buf); 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end_len = os_strlen(end_buf); 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rlen = start_len + imc_len + end_len; 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resp = wpabuf_alloc(rlen); 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (resp == NULL) { 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(start_buf); 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(end_buf); 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(resp, start_buf, start_len); 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(start_buf); 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rpos1 = wpabuf_put(resp, 0); 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rpos = tncc_copy_send_buf(data->tncc, rpos1); 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put(resp, rpos - rpos1); 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(resp, end_buf, end_len); 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(end_buf); 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response", 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_head(resp), wpabuf_len(resp)); 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_buf = resp; 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = PROC_MSG; 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_tnc_build_msg(data, ret, id); 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail: 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == &tmpbuf) 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = NULL; 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_peer_tnc_register(void) 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method *eap; 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC"); 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap == NULL) 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->init = eap_tnc_init; 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->deinit = eap_tnc_deinit; 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->process = eap_tnc_process; 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = eap_peer_method_register(eap); 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_peer_method_free(eap); 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 428