eap_server_tls_common.c revision 289549
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]; 50289549Srpaulo unsigned int flags = 0; 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, 110214501Srpaulo char *label, size_t len) 111214501Srpaulo{ 112289549Srpaulo u8 *out; 113214501Srpaulo 114214501Srpaulo out = os_malloc(len); 115214501Srpaulo if (out == NULL) 116214501Srpaulo return NULL; 117214501Srpaulo 118289549Srpaulo if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, 0, 119289549Srpaulo out, len)) { 120289549Srpaulo os_free(out); 121289549Srpaulo return NULL; 122289549Srpaulo } 123214501Srpaulo 124214501Srpaulo return out; 125214501Srpaulo} 126214501Srpaulo 127214501Srpaulo 128281806Srpaulo/** 129281806Srpaulo * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data 130281806Srpaulo * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 131281806Srpaulo * @data: Data for TLS processing 132281806Srpaulo * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) 133281806Srpaulo * @len: Pointer to length of the session ID generated 134281806Srpaulo * Returns: Pointer to allocated Session-Id on success or %NULL on failure 135281806Srpaulo * 136281806Srpaulo * This function derive the Session-Id based on the TLS session data 137281806Srpaulo * (client/server random and method type). 138281806Srpaulo * 139281806Srpaulo * The caller is responsible for freeing the returned buffer. 140281806Srpaulo */ 141281806Srpaulou8 * eap_server_tls_derive_session_id(struct eap_sm *sm, 142281806Srpaulo struct eap_ssl_data *data, u8 eap_type, 143281806Srpaulo size_t *len) 144281806Srpaulo{ 145289549Srpaulo struct tls_random keys; 146281806Srpaulo u8 *out; 147281806Srpaulo 148289549Srpaulo if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys)) 149281806Srpaulo return NULL; 150281806Srpaulo 151281806Srpaulo if (keys.client_random == NULL || keys.server_random == NULL) 152281806Srpaulo return NULL; 153281806Srpaulo 154281806Srpaulo *len = 1 + keys.client_random_len + keys.server_random_len; 155281806Srpaulo out = os_malloc(*len); 156281806Srpaulo if (out == NULL) 157281806Srpaulo return NULL; 158281806Srpaulo 159281806Srpaulo /* Session-Id = EAP type || client.random || server.random */ 160281806Srpaulo out[0] = eap_type; 161281806Srpaulo os_memcpy(out + 1, keys.client_random, keys.client_random_len); 162281806Srpaulo os_memcpy(out + 1 + keys.client_random_len, keys.server_random, 163281806Srpaulo keys.server_random_len); 164281806Srpaulo 165281806Srpaulo return out; 166281806Srpaulo} 167281806Srpaulo 168281806Srpaulo 169214501Srpaulostruct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, 170214501Srpaulo int eap_type, int version, u8 id) 171214501Srpaulo{ 172214501Srpaulo struct wpabuf *req; 173214501Srpaulo u8 flags; 174214501Srpaulo size_t send_len, plen; 175214501Srpaulo 176214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Generating Request"); 177214501Srpaulo if (data->tls_out == NULL) { 178214501Srpaulo wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__); 179214501Srpaulo return NULL; 180214501Srpaulo } 181214501Srpaulo 182214501Srpaulo flags = version; 183214501Srpaulo send_len = wpabuf_len(data->tls_out) - data->tls_out_pos; 184214501Srpaulo if (1 + send_len > data->tls_out_limit) { 185214501Srpaulo send_len = data->tls_out_limit - 1; 186214501Srpaulo flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; 187214501Srpaulo if (data->tls_out_pos == 0) { 188214501Srpaulo flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; 189214501Srpaulo send_len -= 4; 190214501Srpaulo } 191214501Srpaulo } 192214501Srpaulo 193214501Srpaulo plen = 1 + send_len; 194214501Srpaulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) 195214501Srpaulo plen += 4; 196214501Srpaulo 197252726Srpaulo req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id); 198214501Srpaulo if (req == NULL) 199214501Srpaulo return NULL; 200214501Srpaulo 201214501Srpaulo wpabuf_put_u8(req, flags); /* Flags */ 202214501Srpaulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) 203214501Srpaulo wpabuf_put_be32(req, wpabuf_len(data->tls_out)); 204214501Srpaulo 205214501Srpaulo wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos, 206214501Srpaulo send_len); 207214501Srpaulo data->tls_out_pos += send_len; 208214501Srpaulo 209214501Srpaulo if (data->tls_out_pos == wpabuf_len(data->tls_out)) { 210214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " 211214501Srpaulo "(message sent completely)", 212214501Srpaulo (unsigned long) send_len); 213214501Srpaulo wpabuf_free(data->tls_out); 214214501Srpaulo data->tls_out = NULL; 215214501Srpaulo data->tls_out_pos = 0; 216214501Srpaulo data->state = MSG; 217214501Srpaulo } else { 218214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " 219214501Srpaulo "(%lu more to send)", (unsigned long) send_len, 220214501Srpaulo (unsigned long) wpabuf_len(data->tls_out) - 221214501Srpaulo data->tls_out_pos); 222214501Srpaulo data->state = WAIT_FRAG_ACK; 223214501Srpaulo } 224214501Srpaulo 225214501Srpaulo return req; 226214501Srpaulo} 227214501Srpaulo 228214501Srpaulo 229214501Srpaulostruct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version) 230214501Srpaulo{ 231214501Srpaulo struct wpabuf *req; 232214501Srpaulo 233252726Srpaulo req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id); 234214501Srpaulo if (req == NULL) 235214501Srpaulo return NULL; 236214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Building ACK"); 237214501Srpaulo wpabuf_put_u8(req, version); /* Flags */ 238214501Srpaulo return req; 239214501Srpaulo} 240214501Srpaulo 241214501Srpaulo 242214501Srpaulostatic int eap_server_tls_process_cont(struct eap_ssl_data *data, 243214501Srpaulo const u8 *buf, size_t len) 244214501Srpaulo{ 245214501Srpaulo /* Process continuation of a pending message */ 246214501Srpaulo if (len > wpabuf_tailroom(data->tls_in)) { 247214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Fragment overflow"); 248214501Srpaulo return -1; 249214501Srpaulo } 250214501Srpaulo 251214501Srpaulo wpabuf_put_data(data->tls_in, buf, len); 252214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu " 253214501Srpaulo "bytes more", (unsigned long) len, 254214501Srpaulo (unsigned long) wpabuf_tailroom(data->tls_in)); 255214501Srpaulo 256214501Srpaulo return 0; 257214501Srpaulo} 258214501Srpaulo 259214501Srpaulo 260214501Srpaulostatic int eap_server_tls_process_fragment(struct eap_ssl_data *data, 261214501Srpaulo u8 flags, u32 message_length, 262214501Srpaulo const u8 *buf, size_t len) 263214501Srpaulo{ 264214501Srpaulo /* Process a fragment that is not the last one of the message */ 265214501Srpaulo if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) { 266214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a " 267214501Srpaulo "fragmented packet"); 268214501Srpaulo return -1; 269214501Srpaulo } 270214501Srpaulo 271214501Srpaulo if (data->tls_in == NULL) { 272214501Srpaulo /* First fragment of the message */ 273214501Srpaulo 274214501Srpaulo /* Limit length to avoid rogue peers from causing large 275214501Srpaulo * memory allocations. */ 276214501Srpaulo if (message_length > 65536) { 277214501Srpaulo wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size" 278214501Srpaulo " over 64 kB)"); 279214501Srpaulo return -1; 280214501Srpaulo } 281214501Srpaulo 282243419Scperciva if (len > message_length) { 283243419Scperciva wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in " 284243419Scperciva "first fragment of frame (TLS Message " 285243419Scperciva "Length %d bytes)", 286243419Scperciva (int) len, (int) message_length); 287243419Scperciva return -1; 288243419Scperciva } 289243419Scperciva 290214501Srpaulo data->tls_in = wpabuf_alloc(message_length); 291214501Srpaulo if (data->tls_in == NULL) { 292214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: No memory for message"); 293214501Srpaulo return -1; 294214501Srpaulo } 295214501Srpaulo wpabuf_put_data(data->tls_in, buf, len); 296214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first " 297214501Srpaulo "fragment, waiting for %lu bytes more", 298214501Srpaulo (unsigned long) len, 299214501Srpaulo (unsigned long) wpabuf_tailroom(data->tls_in)); 300214501Srpaulo } 301214501Srpaulo 302214501Srpaulo return 0; 303214501Srpaulo} 304214501Srpaulo 305214501Srpaulo 306214501Srpauloint eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) 307214501Srpaulo{ 308214501Srpaulo if (data->tls_out) { 309214501Srpaulo /* This should not happen.. */ 310214501Srpaulo wpa_printf(MSG_INFO, "SSL: pending tls_out data when " 311214501Srpaulo "processing new message"); 312214501Srpaulo wpabuf_free(data->tls_out); 313214501Srpaulo WPA_ASSERT(data->tls_out == NULL); 314214501Srpaulo } 315214501Srpaulo 316214501Srpaulo data->tls_out = tls_connection_server_handshake(sm->ssl_ctx, 317214501Srpaulo data->conn, 318214501Srpaulo data->tls_in, NULL); 319214501Srpaulo if (data->tls_out == NULL) { 320214501Srpaulo wpa_printf(MSG_INFO, "SSL: TLS processing failed"); 321214501Srpaulo return -1; 322214501Srpaulo } 323214501Srpaulo if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { 324214501Srpaulo /* TLS processing has failed - return error */ 325214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " 326214501Srpaulo "report error"); 327214501Srpaulo return -1; 328214501Srpaulo } 329214501Srpaulo 330214501Srpaulo return 0; 331214501Srpaulo} 332214501Srpaulo 333214501Srpaulo 334214501Srpaulostatic int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags, 335214501Srpaulo const u8 **pos, size_t *left) 336214501Srpaulo{ 337214501Srpaulo unsigned int tls_msg_len = 0; 338214501Srpaulo const u8 *end = *pos + *left; 339214501Srpaulo 340214501Srpaulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { 341214501Srpaulo if (*left < 4) { 342214501Srpaulo wpa_printf(MSG_INFO, "SSL: Short frame with TLS " 343214501Srpaulo "length"); 344214501Srpaulo return -1; 345214501Srpaulo } 346214501Srpaulo tls_msg_len = WPA_GET_BE32(*pos); 347214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", 348214501Srpaulo tls_msg_len); 349214501Srpaulo *pos += 4; 350214501Srpaulo *left -= 4; 351252726Srpaulo 352252726Srpaulo if (*left > tls_msg_len) { 353252726Srpaulo wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " 354252726Srpaulo "bytes) smaller than this fragment (%d " 355252726Srpaulo "bytes)", (int) tls_msg_len, (int) *left); 356252726Srpaulo return -1; 357252726Srpaulo } 358214501Srpaulo } 359214501Srpaulo 360214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x " 361214501Srpaulo "Message Length %u", flags, tls_msg_len); 362214501Srpaulo 363214501Srpaulo if (data->state == WAIT_FRAG_ACK) { 364214501Srpaulo if (*left != 0) { 365214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in " 366214501Srpaulo "WAIT_FRAG_ACK state"); 367214501Srpaulo return -1; 368214501Srpaulo } 369214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged"); 370214501Srpaulo return 1; 371214501Srpaulo } 372214501Srpaulo 373214501Srpaulo if (data->tls_in && 374214501Srpaulo eap_server_tls_process_cont(data, *pos, end - *pos) < 0) 375214501Srpaulo return -1; 376214501Srpaulo 377214501Srpaulo if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) { 378214501Srpaulo if (eap_server_tls_process_fragment(data, flags, tls_msg_len, 379214501Srpaulo *pos, end - *pos) < 0) 380214501Srpaulo return -1; 381214501Srpaulo 382214501Srpaulo data->state = FRAG_ACK; 383214501Srpaulo return 1; 384214501Srpaulo } 385214501Srpaulo 386214501Srpaulo if (data->state == FRAG_ACK) { 387214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: All fragments received"); 388214501Srpaulo data->state = MSG; 389214501Srpaulo } 390214501Srpaulo 391214501Srpaulo if (data->tls_in == NULL) { 392214501Srpaulo /* Wrap unfragmented messages as wpabuf without extra copy */ 393214501Srpaulo wpabuf_set(&data->tmpbuf, *pos, end - *pos); 394214501Srpaulo data->tls_in = &data->tmpbuf; 395214501Srpaulo } 396214501Srpaulo 397214501Srpaulo return 0; 398214501Srpaulo} 399214501Srpaulo 400214501Srpaulo 401214501Srpaulostatic void eap_server_tls_free_in_buf(struct eap_ssl_data *data) 402214501Srpaulo{ 403214501Srpaulo if (data->tls_in != &data->tmpbuf) 404214501Srpaulo wpabuf_free(data->tls_in); 405214501Srpaulo data->tls_in = NULL; 406214501Srpaulo} 407214501Srpaulo 408214501Srpaulo 409214501Srpaulostruct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, 410214501Srpaulo struct eap_ssl_data *data, 411214501Srpaulo const struct wpabuf *plain) 412214501Srpaulo{ 413214501Srpaulo struct wpabuf *buf; 414214501Srpaulo 415214501Srpaulo buf = tls_connection_encrypt(sm->ssl_ctx, data->conn, 416214501Srpaulo plain); 417214501Srpaulo if (buf == NULL) { 418214501Srpaulo wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data"); 419214501Srpaulo return NULL; 420214501Srpaulo } 421214501Srpaulo 422214501Srpaulo return buf; 423214501Srpaulo} 424214501Srpaulo 425214501Srpaulo 426214501Srpauloint eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, 427214501Srpaulo struct wpabuf *respData, void *priv, int eap_type, 428214501Srpaulo int (*proc_version)(struct eap_sm *sm, void *priv, 429214501Srpaulo int peer_version), 430214501Srpaulo void (*proc_msg)(struct eap_sm *sm, void *priv, 431214501Srpaulo const struct wpabuf *respData)) 432214501Srpaulo{ 433214501Srpaulo const u8 *pos; 434214501Srpaulo u8 flags; 435214501Srpaulo size_t left; 436214501Srpaulo int ret, res = 0; 437214501Srpaulo 438252726Srpaulo if (eap_type == EAP_UNAUTH_TLS_TYPE) 439252726Srpaulo pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, 440252726Srpaulo EAP_VENDOR_TYPE_UNAUTH_TLS, respData, 441252726Srpaulo &left); 442281806Srpaulo else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE) 443281806Srpaulo pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW, 444281806Srpaulo EAP_VENDOR_WFA_UNAUTH_TLS, respData, 445281806Srpaulo &left); 446252726Srpaulo else 447252726Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, 448252726Srpaulo &left); 449214501Srpaulo if (pos == NULL || left < 1) 450214501Srpaulo return 0; /* Should not happen - frame already validated */ 451214501Srpaulo flags = *pos++; 452214501Srpaulo left--; 453214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x", 454214501Srpaulo (unsigned long) wpabuf_len(respData), flags); 455214501Srpaulo 456214501Srpaulo if (proc_version && 457214501Srpaulo proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0) 458214501Srpaulo return -1; 459214501Srpaulo 460214501Srpaulo ret = eap_server_tls_reassemble(data, flags, &pos, &left); 461214501Srpaulo if (ret < 0) { 462214501Srpaulo res = -1; 463214501Srpaulo goto done; 464214501Srpaulo } else if (ret == 1) 465214501Srpaulo return 0; 466214501Srpaulo 467214501Srpaulo if (proc_msg) 468214501Srpaulo proc_msg(sm, priv, respData); 469214501Srpaulo 470214501Srpaulo if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) { 471214501Srpaulo wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in " 472214501Srpaulo "TLS processing"); 473214501Srpaulo res = -1; 474214501Srpaulo } 475214501Srpaulo 476214501Srpaulodone: 477214501Srpaulo eap_server_tls_free_in_buf(data); 478214501Srpaulo 479214501Srpaulo return res; 480214501Srpaulo} 481