1214501Srpaulo/* 2214501Srpaulo * EAP-TLS/PEAP/TTLS/FAST server common functions 3214501Srpaulo * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12214501Srpaulo#include "crypto/sha1.h" 13214501Srpaulo#include "crypto/tls.h" 14214501Srpaulo#include "eap_i.h" 15214501Srpaulo#include "eap_tls_common.h" 16214501Srpaulo 17214501Srpaulo 18214501Srpaulostatic void eap_server_tls_free_in_buf(struct eap_ssl_data *data); 19214501Srpaulo 20214501Srpaulo 21252726Srpaulostruct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, 22252726Srpaulo u8 code, u8 identifier) 23252726Srpaulo{ 24252726Srpaulo if (type == EAP_UNAUTH_TLS_TYPE) 25252726Srpaulo return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, 26252726Srpaulo EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, 27252726Srpaulo code, identifier); 28281806Srpaulo else if (type == EAP_WFA_UNAUTH_TLS_TYPE) 29281806Srpaulo return eap_msg_alloc(EAP_VENDOR_WFA_NEW, 30281806Srpaulo EAP_VENDOR_WFA_UNAUTH_TLS, payload_len, 31281806Srpaulo code, identifier); 32252726Srpaulo return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, 33252726Srpaulo identifier); 34252726Srpaulo} 35252726Srpaulo 36252726Srpaulo 37281806Srpaulo#ifdef CONFIG_TLS_INTERNAL 38281806Srpaulostatic void eap_server_tls_log_cb(void *ctx, const char *msg) 39281806Srpaulo{ 40281806Srpaulo struct eap_sm *sm = ctx; 41281806Srpaulo eap_log_msg(sm, "TLS: %s", msg); 42281806Srpaulo} 43281806Srpaulo#endif /* CONFIG_TLS_INTERNAL */ 44281806Srpaulo 45281806Srpaulo 46214501Srpauloint eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, 47289549Srpaulo int verify_peer, int eap_type) 48214501Srpaulo{ 49289549Srpaulo u8 session_ctx[8]; 50346981Scy unsigned int flags = sm->tls_flags; 51289549Srpaulo 52281806Srpaulo if (sm->ssl_ctx == NULL) { 53281806Srpaulo wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method"); 54281806Srpaulo return -1; 55281806Srpaulo } 56281806Srpaulo 57214501Srpaulo data->eap = sm; 58214501Srpaulo data->phase2 = sm->init_phase2; 59214501Srpaulo 60214501Srpaulo data->conn = tls_connection_init(sm->ssl_ctx); 61214501Srpaulo if (data->conn == NULL) { 62214501Srpaulo wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " 63214501Srpaulo "connection"); 64214501Srpaulo return -1; 65214501Srpaulo } 66214501Srpaulo 67281806Srpaulo#ifdef CONFIG_TLS_INTERNAL 68281806Srpaulo tls_connection_set_log_cb(data->conn, eap_server_tls_log_cb, sm); 69281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 70281806Srpaulo tls_connection_set_test_flags(data->conn, sm->tls_test_flags); 71281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 72281806Srpaulo#endif /* CONFIG_TLS_INTERNAL */ 73281806Srpaulo 74289549Srpaulo if (eap_type != EAP_TYPE_FAST) 75289549Srpaulo flags |= TLS_CONN_DISABLE_SESSION_TICKET; 76289549Srpaulo os_memcpy(session_ctx, "hostapd", 7); 77289549Srpaulo session_ctx[7] = (u8) eap_type; 78289549Srpaulo if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer, 79289549Srpaulo flags, session_ctx, 80289549Srpaulo sizeof(session_ctx))) { 81214501Srpaulo wpa_printf(MSG_INFO, "SSL: Failed to configure verification " 82214501Srpaulo "of TLS peer certificate"); 83214501Srpaulo tls_connection_deinit(sm->ssl_ctx, data->conn); 84214501Srpaulo data->conn = NULL; 85214501Srpaulo return -1; 86214501Srpaulo } 87214501Srpaulo 88252726Srpaulo data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398; 89214501Srpaulo if (data->phase2) { 90214501Srpaulo /* Limit the fragment size in the inner TLS authentication 91214501Srpaulo * since the outer authentication with EAP-PEAP does not yet 92214501Srpaulo * support fragmentation */ 93214501Srpaulo if (data->tls_out_limit > 100) 94214501Srpaulo data->tls_out_limit -= 100; 95214501Srpaulo } 96214501Srpaulo return 0; 97214501Srpaulo} 98214501Srpaulo 99214501Srpaulo 100214501Srpaulovoid eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) 101214501Srpaulo{ 102214501Srpaulo tls_connection_deinit(sm->ssl_ctx, data->conn); 103214501Srpaulo eap_server_tls_free_in_buf(data); 104214501Srpaulo wpabuf_free(data->tls_out); 105214501Srpaulo data->tls_out = NULL; 106214501Srpaulo} 107214501Srpaulo 108214501Srpaulo 109214501Srpaulou8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, 110346981Scy const char *label, const u8 *context, 111346981Scy size_t context_len, size_t len) 112214501Srpaulo{ 113289549Srpaulo u8 *out; 114214501Srpaulo 115214501Srpaulo out = os_malloc(len); 116214501Srpaulo if (out == NULL) 117214501Srpaulo return NULL; 118214501Srpaulo 119346981Scy if (tls_connection_export_key(sm->ssl_ctx, data->conn, label, 120346981Scy context, context_len, out, len)) { 121289549Srpaulo os_free(out); 122289549Srpaulo return NULL; 123289549Srpaulo } 124214501Srpaulo 125214501Srpaulo return out; 126214501Srpaulo} 127214501Srpaulo 128214501Srpaulo 129281806Srpaulo/** 130281806Srpaulo * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data 131281806Srpaulo * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 132281806Srpaulo * @data: Data for TLS processing 133281806Srpaulo * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) 134281806Srpaulo * @len: Pointer to length of the session ID generated 135281806Srpaulo * Returns: Pointer to allocated Session-Id on success or %NULL on failure 136281806Srpaulo * 137281806Srpaulo * This function derive the Session-Id based on the TLS session data 138281806Srpaulo * (client/server random and method type). 139281806Srpaulo * 140281806Srpaulo * The caller is responsible for freeing the returned buffer. 141281806Srpaulo */ 142281806Srpaulou8 * eap_server_tls_derive_session_id(struct eap_sm *sm, 143281806Srpaulo struct eap_ssl_data *data, u8 eap_type, 144281806Srpaulo size_t *len) 145281806Srpaulo{ 146289549Srpaulo struct tls_random keys; 147281806Srpaulo u8 *out; 148351611Scy const u8 context[] = { EAP_TYPE_TLS }; 149281806Srpaulo 150346981Scy if (eap_type == EAP_TYPE_TLS && data->tls_v13) { 151346981Scy u8 *id, *method_id; 152346981Scy 153346981Scy /* Session-Id = <EAP-Type> || Method-Id 154346981Scy * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id", 155351611Scy * Type-Code, 64) 156346981Scy */ 157346981Scy *len = 1 + 64; 158346981Scy id = os_malloc(*len); 159346981Scy if (!id) 160346981Scy return NULL; 161346981Scy method_id = eap_server_tls_derive_key( 162351611Scy sm, data, "EXPORTER_EAP_TLS_Method-Id", context, 1, 64); 163346981Scy if (!method_id) { 164346981Scy os_free(id); 165346981Scy return NULL; 166346981Scy } 167346981Scy id[0] = eap_type; 168346981Scy os_memcpy(id + 1, method_id, 64); 169346981Scy os_free(method_id); 170346981Scy return id; 171346981Scy } 172346981Scy 173289549Srpaulo if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys)) 174281806Srpaulo return NULL; 175281806Srpaulo 176281806Srpaulo if (keys.client_random == NULL || keys.server_random == NULL) 177281806Srpaulo return NULL; 178281806Srpaulo 179281806Srpaulo *len = 1 + keys.client_random_len + keys.server_random_len; 180281806Srpaulo out = os_malloc(*len); 181281806Srpaulo if (out == NULL) 182281806Srpaulo return NULL; 183281806Srpaulo 184281806Srpaulo /* Session-Id = EAP type || client.random || server.random */ 185281806Srpaulo out[0] = eap_type; 186281806Srpaulo os_memcpy(out + 1, keys.client_random, keys.client_random_len); 187281806Srpaulo os_memcpy(out + 1 + keys.client_random_len, keys.server_random, 188281806Srpaulo keys.server_random_len); 189281806Srpaulo 190281806Srpaulo return out; 191281806Srpaulo} 192281806Srpaulo 193281806Srpaulo 194214501Srpaulostruct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, 195214501Srpaulo int eap_type, int version, u8 id) 196214501Srpaulo{ 197214501Srpaulo struct wpabuf *req; 198214501Srpaulo u8 flags; 199214501Srpaulo size_t send_len, plen; 200214501Srpaulo 201214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Generating Request"); 202214501Srpaulo if (data->tls_out == NULL) { 203214501Srpaulo wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__); 204214501Srpaulo return NULL; 205214501Srpaulo } 206214501Srpaulo 207214501Srpaulo flags = version; 208214501Srpaulo send_len = wpabuf_len(data->tls_out) - data->tls_out_pos; 209214501Srpaulo if (1 + send_len > data->tls_out_limit) { 210214501Srpaulo send_len = data->tls_out_limit - 1; 211214501Srpaulo flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; 212214501Srpaulo if (data->tls_out_pos == 0) { 213214501Srpaulo flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; 214214501Srpaulo send_len -= 4; 215214501Srpaulo } 216214501Srpaulo } 217214501Srpaulo 218214501Srpaulo plen = 1 + send_len; 219214501Srpaulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) 220214501Srpaulo plen += 4; 221214501Srpaulo 222252726Srpaulo req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id); 223214501Srpaulo if (req == NULL) 224214501Srpaulo return NULL; 225214501Srpaulo 226214501Srpaulo wpabuf_put_u8(req, flags); /* Flags */ 227214501Srpaulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) 228214501Srpaulo wpabuf_put_be32(req, wpabuf_len(data->tls_out)); 229214501Srpaulo 230214501Srpaulo wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos, 231214501Srpaulo send_len); 232214501Srpaulo data->tls_out_pos += send_len; 233214501Srpaulo 234214501Srpaulo if (data->tls_out_pos == wpabuf_len(data->tls_out)) { 235214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " 236214501Srpaulo "(message sent completely)", 237214501Srpaulo (unsigned long) send_len); 238214501Srpaulo wpabuf_free(data->tls_out); 239214501Srpaulo data->tls_out = NULL; 240214501Srpaulo data->tls_out_pos = 0; 241214501Srpaulo data->state = MSG; 242214501Srpaulo } else { 243214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " 244214501Srpaulo "(%lu more to send)", (unsigned long) send_len, 245214501Srpaulo (unsigned long) wpabuf_len(data->tls_out) - 246214501Srpaulo data->tls_out_pos); 247214501Srpaulo data->state = WAIT_FRAG_ACK; 248214501Srpaulo } 249214501Srpaulo 250214501Srpaulo return req; 251214501Srpaulo} 252214501Srpaulo 253214501Srpaulo 254214501Srpaulostruct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version) 255214501Srpaulo{ 256214501Srpaulo struct wpabuf *req; 257214501Srpaulo 258252726Srpaulo req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id); 259214501Srpaulo if (req == NULL) 260214501Srpaulo return NULL; 261214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Building ACK"); 262214501Srpaulo wpabuf_put_u8(req, version); /* Flags */ 263214501Srpaulo return req; 264214501Srpaulo} 265214501Srpaulo 266214501Srpaulo 267214501Srpaulostatic int eap_server_tls_process_cont(struct eap_ssl_data *data, 268214501Srpaulo const u8 *buf, size_t len) 269214501Srpaulo{ 270214501Srpaulo /* Process continuation of a pending message */ 271214501Srpaulo if (len > wpabuf_tailroom(data->tls_in)) { 272214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Fragment overflow"); 273214501Srpaulo return -1; 274214501Srpaulo } 275214501Srpaulo 276214501Srpaulo wpabuf_put_data(data->tls_in, buf, len); 277214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu " 278214501Srpaulo "bytes more", (unsigned long) len, 279214501Srpaulo (unsigned long) wpabuf_tailroom(data->tls_in)); 280214501Srpaulo 281214501Srpaulo return 0; 282214501Srpaulo} 283214501Srpaulo 284214501Srpaulo 285214501Srpaulostatic int eap_server_tls_process_fragment(struct eap_ssl_data *data, 286214501Srpaulo u8 flags, u32 message_length, 287214501Srpaulo const u8 *buf, size_t len) 288214501Srpaulo{ 289214501Srpaulo /* Process a fragment that is not the last one of the message */ 290214501Srpaulo if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) { 291214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a " 292214501Srpaulo "fragmented packet"); 293214501Srpaulo return -1; 294214501Srpaulo } 295214501Srpaulo 296214501Srpaulo if (data->tls_in == NULL) { 297214501Srpaulo /* First fragment of the message */ 298214501Srpaulo 299214501Srpaulo /* Limit length to avoid rogue peers from causing large 300214501Srpaulo * memory allocations. */ 301214501Srpaulo if (message_length > 65536) { 302214501Srpaulo wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size" 303214501Srpaulo " over 64 kB)"); 304214501Srpaulo return -1; 305214501Srpaulo } 306214501Srpaulo 307243419Scperciva if (len > message_length) { 308243419Scperciva wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in " 309243419Scperciva "first fragment of frame (TLS Message " 310243419Scperciva "Length %d bytes)", 311243419Scperciva (int) len, (int) message_length); 312243419Scperciva return -1; 313243419Scperciva } 314243419Scperciva 315214501Srpaulo data->tls_in = wpabuf_alloc(message_length); 316214501Srpaulo if (data->tls_in == NULL) { 317214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: No memory for message"); 318214501Srpaulo return -1; 319214501Srpaulo } 320214501Srpaulo wpabuf_put_data(data->tls_in, buf, len); 321214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first " 322214501Srpaulo "fragment, waiting for %lu bytes more", 323214501Srpaulo (unsigned long) len, 324214501Srpaulo (unsigned long) wpabuf_tailroom(data->tls_in)); 325214501Srpaulo } 326214501Srpaulo 327214501Srpaulo return 0; 328214501Srpaulo} 329214501Srpaulo 330214501Srpaulo 331214501Srpauloint eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) 332214501Srpaulo{ 333346981Scy char buf[20]; 334346981Scy 335214501Srpaulo if (data->tls_out) { 336214501Srpaulo /* This should not happen.. */ 337214501Srpaulo wpa_printf(MSG_INFO, "SSL: pending tls_out data when " 338214501Srpaulo "processing new message"); 339214501Srpaulo wpabuf_free(data->tls_out); 340214501Srpaulo WPA_ASSERT(data->tls_out == NULL); 341214501Srpaulo } 342214501Srpaulo 343214501Srpaulo data->tls_out = tls_connection_server_handshake(sm->ssl_ctx, 344214501Srpaulo data->conn, 345214501Srpaulo data->tls_in, NULL); 346214501Srpaulo if (data->tls_out == NULL) { 347214501Srpaulo wpa_printf(MSG_INFO, "SSL: TLS processing failed"); 348214501Srpaulo return -1; 349214501Srpaulo } 350214501Srpaulo if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { 351214501Srpaulo /* TLS processing has failed - return error */ 352214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " 353214501Srpaulo "report error"); 354214501Srpaulo return -1; 355214501Srpaulo } 356214501Srpaulo 357346981Scy if (tls_get_version(sm->ssl_ctx, data->conn, buf, sizeof(buf)) == 0) { 358346981Scy wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf); 359346981Scy data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0; 360346981Scy } 361346981Scy 362346981Scy if (!sm->serial_num && 363346981Scy tls_connection_established(sm->ssl_ctx, data->conn)) 364346981Scy sm->serial_num = tls_connection_peer_serial_num(sm->ssl_ctx, 365346981Scy data->conn); 366346981Scy 367214501Srpaulo return 0; 368214501Srpaulo} 369214501Srpaulo 370214501Srpaulo 371214501Srpaulostatic int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags, 372214501Srpaulo const u8 **pos, size_t *left) 373214501Srpaulo{ 374214501Srpaulo unsigned int tls_msg_len = 0; 375214501Srpaulo const u8 *end = *pos + *left; 376214501Srpaulo 377351611Scy wpa_hexdump(MSG_MSGDUMP, "SSL: Received data", *pos, *left); 378351611Scy 379214501Srpaulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { 380214501Srpaulo if (*left < 4) { 381214501Srpaulo wpa_printf(MSG_INFO, "SSL: Short frame with TLS " 382214501Srpaulo "length"); 383214501Srpaulo return -1; 384214501Srpaulo } 385214501Srpaulo tls_msg_len = WPA_GET_BE32(*pos); 386214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", 387214501Srpaulo tls_msg_len); 388214501Srpaulo *pos += 4; 389214501Srpaulo *left -= 4; 390252726Srpaulo 391252726Srpaulo if (*left > tls_msg_len) { 392252726Srpaulo wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " 393252726Srpaulo "bytes) smaller than this fragment (%d " 394252726Srpaulo "bytes)", (int) tls_msg_len, (int) *left); 395252726Srpaulo return -1; 396252726Srpaulo } 397214501Srpaulo } 398214501Srpaulo 399214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x " 400214501Srpaulo "Message Length %u", flags, tls_msg_len); 401214501Srpaulo 402214501Srpaulo if (data->state == WAIT_FRAG_ACK) { 403214501Srpaulo if (*left != 0) { 404214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in " 405214501Srpaulo "WAIT_FRAG_ACK state"); 406214501Srpaulo return -1; 407214501Srpaulo } 408214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged"); 409214501Srpaulo return 1; 410214501Srpaulo } 411214501Srpaulo 412214501Srpaulo if (data->tls_in && 413214501Srpaulo eap_server_tls_process_cont(data, *pos, end - *pos) < 0) 414214501Srpaulo return -1; 415346981Scy 416214501Srpaulo if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) { 417214501Srpaulo if (eap_server_tls_process_fragment(data, flags, tls_msg_len, 418214501Srpaulo *pos, end - *pos) < 0) 419214501Srpaulo return -1; 420214501Srpaulo 421214501Srpaulo data->state = FRAG_ACK; 422214501Srpaulo return 1; 423214501Srpaulo } 424214501Srpaulo 425214501Srpaulo if (data->state == FRAG_ACK) { 426214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: All fragments received"); 427214501Srpaulo data->state = MSG; 428214501Srpaulo } 429214501Srpaulo 430214501Srpaulo if (data->tls_in == NULL) { 431214501Srpaulo /* Wrap unfragmented messages as wpabuf without extra copy */ 432214501Srpaulo wpabuf_set(&data->tmpbuf, *pos, end - *pos); 433214501Srpaulo data->tls_in = &data->tmpbuf; 434214501Srpaulo } 435214501Srpaulo 436214501Srpaulo return 0; 437214501Srpaulo} 438214501Srpaulo 439214501Srpaulo 440214501Srpaulostatic void eap_server_tls_free_in_buf(struct eap_ssl_data *data) 441214501Srpaulo{ 442214501Srpaulo if (data->tls_in != &data->tmpbuf) 443214501Srpaulo wpabuf_free(data->tls_in); 444214501Srpaulo data->tls_in = NULL; 445214501Srpaulo} 446214501Srpaulo 447214501Srpaulo 448214501Srpaulostruct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, 449214501Srpaulo struct eap_ssl_data *data, 450214501Srpaulo const struct wpabuf *plain) 451214501Srpaulo{ 452214501Srpaulo struct wpabuf *buf; 453214501Srpaulo 454214501Srpaulo buf = tls_connection_encrypt(sm->ssl_ctx, data->conn, 455214501Srpaulo plain); 456214501Srpaulo if (buf == NULL) { 457214501Srpaulo wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data"); 458214501Srpaulo return NULL; 459214501Srpaulo } 460214501Srpaulo 461214501Srpaulo return buf; 462214501Srpaulo} 463214501Srpaulo 464214501Srpaulo 465214501Srpauloint eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, 466214501Srpaulo struct wpabuf *respData, void *priv, int eap_type, 467214501Srpaulo int (*proc_version)(struct eap_sm *sm, void *priv, 468214501Srpaulo int peer_version), 469214501Srpaulo void (*proc_msg)(struct eap_sm *sm, void *priv, 470214501Srpaulo const struct wpabuf *respData)) 471214501Srpaulo{ 472214501Srpaulo const u8 *pos; 473214501Srpaulo u8 flags; 474214501Srpaulo size_t left; 475214501Srpaulo int ret, res = 0; 476214501Srpaulo 477252726Srpaulo if (eap_type == EAP_UNAUTH_TLS_TYPE) 478252726Srpaulo pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, 479252726Srpaulo EAP_VENDOR_TYPE_UNAUTH_TLS, respData, 480252726Srpaulo &left); 481281806Srpaulo else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE) 482281806Srpaulo pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW, 483281806Srpaulo EAP_VENDOR_WFA_UNAUTH_TLS, respData, 484281806Srpaulo &left); 485252726Srpaulo else 486252726Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, 487252726Srpaulo &left); 488214501Srpaulo if (pos == NULL || left < 1) 489214501Srpaulo return 0; /* Should not happen - frame already validated */ 490214501Srpaulo flags = *pos++; 491214501Srpaulo left--; 492214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x", 493214501Srpaulo (unsigned long) wpabuf_len(respData), flags); 494214501Srpaulo 495214501Srpaulo if (proc_version && 496214501Srpaulo proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0) 497214501Srpaulo return -1; 498214501Srpaulo 499214501Srpaulo ret = eap_server_tls_reassemble(data, flags, &pos, &left); 500214501Srpaulo if (ret < 0) { 501214501Srpaulo res = -1; 502214501Srpaulo goto done; 503214501Srpaulo } else if (ret == 1) 504214501Srpaulo return 0; 505214501Srpaulo 506214501Srpaulo if (proc_msg) 507214501Srpaulo proc_msg(sm, priv, respData); 508214501Srpaulo 509214501Srpaulo if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) { 510214501Srpaulo wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in " 511214501Srpaulo "TLS processing"); 512214501Srpaulo res = -1; 513214501Srpaulo } 514214501Srpaulo 515214501Srpaulodone: 516214501Srpaulo eap_server_tls_free_in_buf(data); 517214501Srpaulo 518214501Srpaulo return res; 519214501Srpaulo} 520