1e28a4053SRui Paulo /* 2e28a4053SRui Paulo * EAP-TLS/PEAP/TTLS/FAST server common functions 3e28a4053SRui Paulo * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> 4e28a4053SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7e28a4053SRui Paulo */ 8e28a4053SRui Paulo 9e28a4053SRui Paulo #include "includes.h" 10e28a4053SRui Paulo 11e28a4053SRui Paulo #include "common.h" 12e28a4053SRui Paulo #include "crypto/sha1.h" 13e28a4053SRui Paulo #include "crypto/tls.h" 14e28a4053SRui Paulo #include "eap_i.h" 15e28a4053SRui Paulo #include "eap_tls_common.h" 16e28a4053SRui Paulo 17e28a4053SRui Paulo 18e28a4053SRui Paulo static void eap_server_tls_free_in_buf(struct eap_ssl_data *data); 19e28a4053SRui Paulo 20e28a4053SRui Paulo 21c1d255d3SCy Schubert struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len, 22f05cddf9SRui Paulo u8 code, u8 identifier) 23f05cddf9SRui Paulo { 24f05cddf9SRui Paulo if (type == EAP_UNAUTH_TLS_TYPE) 25f05cddf9SRui Paulo return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, 26f05cddf9SRui Paulo EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, 27f05cddf9SRui Paulo code, identifier); 285b9c547cSRui Paulo else if (type == EAP_WFA_UNAUTH_TLS_TYPE) 295b9c547cSRui Paulo return eap_msg_alloc(EAP_VENDOR_WFA_NEW, 305b9c547cSRui Paulo EAP_VENDOR_WFA_UNAUTH_TLS, payload_len, 315b9c547cSRui Paulo code, identifier); 32f05cddf9SRui Paulo return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, 33f05cddf9SRui Paulo identifier); 34f05cddf9SRui Paulo } 35f05cddf9SRui Paulo 36f05cddf9SRui Paulo 375b9c547cSRui Paulo #ifdef CONFIG_TLS_INTERNAL 385b9c547cSRui Paulo static void eap_server_tls_log_cb(void *ctx, const char *msg) 395b9c547cSRui Paulo { 405b9c547cSRui Paulo struct eap_sm *sm = ctx; 415b9c547cSRui Paulo eap_log_msg(sm, "TLS: %s", msg); 425b9c547cSRui Paulo } 435b9c547cSRui Paulo #endif /* CONFIG_TLS_INTERNAL */ 445b9c547cSRui Paulo 455b9c547cSRui Paulo 46e28a4053SRui Paulo int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, 47325151a3SRui Paulo int verify_peer, int eap_type) 48e28a4053SRui Paulo { 49325151a3SRui Paulo u8 session_ctx[8]; 50c1d255d3SCy Schubert unsigned int flags = sm->cfg->tls_flags; 51325151a3SRui Paulo 52c1d255d3SCy Schubert if (!sm->cfg->ssl_ctx) { 535b9c547cSRui Paulo wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method"); 545b9c547cSRui Paulo return -1; 555b9c547cSRui Paulo } 565b9c547cSRui Paulo 57e28a4053SRui Paulo data->eap = sm; 58e28a4053SRui Paulo data->phase2 = sm->init_phase2; 59e28a4053SRui Paulo 60c1d255d3SCy Schubert data->conn = tls_connection_init(sm->cfg->ssl_ctx); 61e28a4053SRui Paulo if (data->conn == NULL) { 62e28a4053SRui Paulo wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " 63e28a4053SRui Paulo "connection"); 64e28a4053SRui Paulo return -1; 65e28a4053SRui Paulo } 66e28a4053SRui Paulo 675b9c547cSRui Paulo #ifdef CONFIG_TLS_INTERNAL 685b9c547cSRui Paulo tls_connection_set_log_cb(data->conn, eap_server_tls_log_cb, sm); 695b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 705b9c547cSRui Paulo tls_connection_set_test_flags(data->conn, sm->tls_test_flags); 715b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 725b9c547cSRui Paulo #endif /* CONFIG_TLS_INTERNAL */ 735b9c547cSRui Paulo 74325151a3SRui Paulo if (eap_type != EAP_TYPE_FAST) 75325151a3SRui Paulo flags |= TLS_CONN_DISABLE_SESSION_TICKET; 76325151a3SRui Paulo os_memcpy(session_ctx, "hostapd", 7); 77325151a3SRui Paulo session_ctx[7] = (u8) eap_type; 78c1d255d3SCy Schubert if (tls_connection_set_verify(sm->cfg->ssl_ctx, data->conn, verify_peer, 79325151a3SRui Paulo flags, session_ctx, 80325151a3SRui Paulo sizeof(session_ctx))) { 81e28a4053SRui Paulo wpa_printf(MSG_INFO, "SSL: Failed to configure verification " 82e28a4053SRui Paulo "of TLS peer certificate"); 83c1d255d3SCy Schubert tls_connection_deinit(sm->cfg->ssl_ctx, data->conn); 84e28a4053SRui Paulo data->conn = NULL; 85e28a4053SRui Paulo return -1; 86e28a4053SRui Paulo } 87e28a4053SRui Paulo 88c1d255d3SCy Schubert data->tls_out_limit = sm->cfg->fragment_size > 0 ? 89c1d255d3SCy Schubert sm->cfg->fragment_size : 1398; 90e28a4053SRui Paulo if (data->phase2) { 91e28a4053SRui Paulo /* Limit the fragment size in the inner TLS authentication 92e28a4053SRui Paulo * since the outer authentication with EAP-PEAP does not yet 93e28a4053SRui Paulo * support fragmentation */ 94e28a4053SRui Paulo if (data->tls_out_limit > 100) 95e28a4053SRui Paulo data->tls_out_limit -= 100; 96e28a4053SRui Paulo } 97*a90b9d01SCy Schubert 98*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 99*a90b9d01SCy Schubert data->skip_prot_success = sm->cfg->skip_prot_success; 100*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 101*a90b9d01SCy Schubert 102e28a4053SRui Paulo return 0; 103e28a4053SRui Paulo } 104e28a4053SRui Paulo 105e28a4053SRui Paulo 106e28a4053SRui Paulo void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) 107e28a4053SRui Paulo { 108c1d255d3SCy Schubert tls_connection_deinit(sm->cfg->ssl_ctx, data->conn); 109e28a4053SRui Paulo eap_server_tls_free_in_buf(data); 110e28a4053SRui Paulo wpabuf_free(data->tls_out); 111e28a4053SRui Paulo data->tls_out = NULL; 112e28a4053SRui Paulo } 113e28a4053SRui Paulo 114e28a4053SRui Paulo 115e28a4053SRui Paulo u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, 1164bc52338SCy Schubert const char *label, const u8 *context, 1174bc52338SCy Schubert size_t context_len, size_t len) 118e28a4053SRui Paulo { 119325151a3SRui Paulo u8 *out; 120e28a4053SRui Paulo 121e28a4053SRui Paulo out = os_malloc(len); 122e28a4053SRui Paulo if (out == NULL) 123e28a4053SRui Paulo return NULL; 124e28a4053SRui Paulo 125c1d255d3SCy Schubert if (tls_connection_export_key(sm->cfg->ssl_ctx, data->conn, label, 1264bc52338SCy Schubert context, context_len, out, len)) { 127e28a4053SRui Paulo os_free(out); 128e28a4053SRui Paulo return NULL; 129e28a4053SRui Paulo } 130e28a4053SRui Paulo 131325151a3SRui Paulo return out; 132325151a3SRui Paulo } 133325151a3SRui Paulo 134e28a4053SRui Paulo 1355b9c547cSRui Paulo /** 1365b9c547cSRui Paulo * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data 1375b9c547cSRui Paulo * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 1385b9c547cSRui Paulo * @data: Data for TLS processing 1395b9c547cSRui Paulo * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) 1405b9c547cSRui Paulo * @len: Pointer to length of the session ID generated 1415b9c547cSRui Paulo * Returns: Pointer to allocated Session-Id on success or %NULL on failure 1425b9c547cSRui Paulo * 1435b9c547cSRui Paulo * This function derive the Session-Id based on the TLS session data 1445b9c547cSRui Paulo * (client/server random and method type). 1455b9c547cSRui Paulo * 1465b9c547cSRui Paulo * The caller is responsible for freeing the returned buffer. 1475b9c547cSRui Paulo */ 1485b9c547cSRui Paulo u8 * eap_server_tls_derive_session_id(struct eap_sm *sm, 1495b9c547cSRui Paulo struct eap_ssl_data *data, u8 eap_type, 1505b9c547cSRui Paulo size_t *len) 1515b9c547cSRui Paulo { 152325151a3SRui Paulo struct tls_random keys; 1535b9c547cSRui Paulo u8 *out; 1545b9c547cSRui Paulo 155c1d255d3SCy Schubert if (data->tls_v13) { 1564bc52338SCy Schubert u8 *id, *method_id; 157c1d255d3SCy Schubert const u8 context[] = { eap_type }; 1584bc52338SCy Schubert 1594bc52338SCy Schubert /* Session-Id = <EAP-Type> || Method-Id 1604bc52338SCy Schubert * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id", 161206b73d0SCy Schubert * Type-Code, 64) 1624bc52338SCy Schubert */ 1634bc52338SCy Schubert *len = 1 + 64; 1644bc52338SCy Schubert id = os_malloc(*len); 1654bc52338SCy Schubert if (!id) 1664bc52338SCy Schubert return NULL; 1674bc52338SCy Schubert method_id = eap_server_tls_derive_key( 168206b73d0SCy Schubert sm, data, "EXPORTER_EAP_TLS_Method-Id", context, 1, 64); 1694bc52338SCy Schubert if (!method_id) { 1704bc52338SCy Schubert os_free(id); 1714bc52338SCy Schubert return NULL; 1724bc52338SCy Schubert } 1734bc52338SCy Schubert id[0] = eap_type; 1744bc52338SCy Schubert os_memcpy(id + 1, method_id, 64); 1754bc52338SCy Schubert os_free(method_id); 1764bc52338SCy Schubert return id; 17785732ac8SCy Schubert } 17885732ac8SCy Schubert 179c1d255d3SCy Schubert if (tls_connection_get_random(sm->cfg->ssl_ctx, data->conn, &keys)) 1805b9c547cSRui Paulo return NULL; 1815b9c547cSRui Paulo 1825b9c547cSRui Paulo if (keys.client_random == NULL || keys.server_random == NULL) 1835b9c547cSRui Paulo return NULL; 1845b9c547cSRui Paulo 1855b9c547cSRui Paulo *len = 1 + keys.client_random_len + keys.server_random_len; 1865b9c547cSRui Paulo out = os_malloc(*len); 1875b9c547cSRui Paulo if (out == NULL) 1885b9c547cSRui Paulo return NULL; 1895b9c547cSRui Paulo 1905b9c547cSRui Paulo /* Session-Id = EAP type || client.random || server.random */ 1915b9c547cSRui Paulo out[0] = eap_type; 1925b9c547cSRui Paulo os_memcpy(out + 1, keys.client_random, keys.client_random_len); 1935b9c547cSRui Paulo os_memcpy(out + 1 + keys.client_random_len, keys.server_random, 1945b9c547cSRui Paulo keys.server_random_len); 1955b9c547cSRui Paulo 1965b9c547cSRui Paulo return out; 1975b9c547cSRui Paulo } 1985b9c547cSRui Paulo 1995b9c547cSRui Paulo 200e28a4053SRui Paulo struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, 201e28a4053SRui Paulo int eap_type, int version, u8 id) 202e28a4053SRui Paulo { 203e28a4053SRui Paulo struct wpabuf *req; 204e28a4053SRui Paulo u8 flags; 205e28a4053SRui Paulo size_t send_len, plen; 206e28a4053SRui Paulo 207e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Generating Request"); 208e28a4053SRui Paulo if (data->tls_out == NULL) { 209e28a4053SRui Paulo wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__); 210e28a4053SRui Paulo return NULL; 211e28a4053SRui Paulo } 212e28a4053SRui Paulo 213e28a4053SRui Paulo flags = version; 214e28a4053SRui Paulo send_len = wpabuf_len(data->tls_out) - data->tls_out_pos; 215e28a4053SRui Paulo if (1 + send_len > data->tls_out_limit) { 216e28a4053SRui Paulo send_len = data->tls_out_limit - 1; 217e28a4053SRui Paulo flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; 218e28a4053SRui Paulo if (data->tls_out_pos == 0) { 219e28a4053SRui Paulo flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; 220e28a4053SRui Paulo send_len -= 4; 221e28a4053SRui Paulo } 222e28a4053SRui Paulo } 223e28a4053SRui Paulo 224e28a4053SRui Paulo plen = 1 + send_len; 225e28a4053SRui Paulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) 226e28a4053SRui Paulo plen += 4; 227e28a4053SRui Paulo 228f05cddf9SRui Paulo req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id); 229e28a4053SRui Paulo if (req == NULL) 230e28a4053SRui Paulo return NULL; 231e28a4053SRui Paulo 232e28a4053SRui Paulo wpabuf_put_u8(req, flags); /* Flags */ 233e28a4053SRui Paulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) 234e28a4053SRui Paulo wpabuf_put_be32(req, wpabuf_len(data->tls_out)); 235e28a4053SRui Paulo 236e28a4053SRui Paulo wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos, 237e28a4053SRui Paulo send_len); 238e28a4053SRui Paulo data->tls_out_pos += send_len; 239e28a4053SRui Paulo 240e28a4053SRui Paulo if (data->tls_out_pos == wpabuf_len(data->tls_out)) { 241e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " 242e28a4053SRui Paulo "(message sent completely)", 243e28a4053SRui Paulo (unsigned long) send_len); 244e28a4053SRui Paulo wpabuf_free(data->tls_out); 245e28a4053SRui Paulo data->tls_out = NULL; 246e28a4053SRui Paulo data->tls_out_pos = 0; 247e28a4053SRui Paulo data->state = MSG; 248e28a4053SRui Paulo } else { 249e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " 250e28a4053SRui Paulo "(%lu more to send)", (unsigned long) send_len, 251e28a4053SRui Paulo (unsigned long) wpabuf_len(data->tls_out) - 252e28a4053SRui Paulo data->tls_out_pos); 253e28a4053SRui Paulo data->state = WAIT_FRAG_ACK; 254e28a4053SRui Paulo } 255e28a4053SRui Paulo 256e28a4053SRui Paulo return req; 257e28a4053SRui Paulo } 258e28a4053SRui Paulo 259e28a4053SRui Paulo 260e28a4053SRui Paulo struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version) 261e28a4053SRui Paulo { 262e28a4053SRui Paulo struct wpabuf *req; 263e28a4053SRui Paulo 264f05cddf9SRui Paulo req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id); 265e28a4053SRui Paulo if (req == NULL) 266e28a4053SRui Paulo return NULL; 267e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Building ACK"); 268e28a4053SRui Paulo wpabuf_put_u8(req, version); /* Flags */ 269e28a4053SRui Paulo return req; 270e28a4053SRui Paulo } 271e28a4053SRui Paulo 272e28a4053SRui Paulo 273e28a4053SRui Paulo static int eap_server_tls_process_cont(struct eap_ssl_data *data, 274e28a4053SRui Paulo const u8 *buf, size_t len) 275e28a4053SRui Paulo { 276e28a4053SRui Paulo /* Process continuation of a pending message */ 277e28a4053SRui Paulo if (len > wpabuf_tailroom(data->tls_in)) { 278e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Fragment overflow"); 279e28a4053SRui Paulo return -1; 280e28a4053SRui Paulo } 281e28a4053SRui Paulo 282e28a4053SRui Paulo wpabuf_put_data(data->tls_in, buf, len); 283e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu " 284e28a4053SRui Paulo "bytes more", (unsigned long) len, 285e28a4053SRui Paulo (unsigned long) wpabuf_tailroom(data->tls_in)); 286e28a4053SRui Paulo 287e28a4053SRui Paulo return 0; 288e28a4053SRui Paulo } 289e28a4053SRui Paulo 290e28a4053SRui Paulo 291e28a4053SRui Paulo static int eap_server_tls_process_fragment(struct eap_ssl_data *data, 292e28a4053SRui Paulo u8 flags, u32 message_length, 293e28a4053SRui Paulo const u8 *buf, size_t len) 294e28a4053SRui Paulo { 295e28a4053SRui Paulo /* Process a fragment that is not the last one of the message */ 296e28a4053SRui Paulo if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) { 297e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a " 298e28a4053SRui Paulo "fragmented packet"); 299e28a4053SRui Paulo return -1; 300e28a4053SRui Paulo } 301e28a4053SRui Paulo 302e28a4053SRui Paulo if (data->tls_in == NULL) { 303e28a4053SRui Paulo /* First fragment of the message */ 304e28a4053SRui Paulo 305e28a4053SRui Paulo /* Limit length to avoid rogue peers from causing large 306e28a4053SRui Paulo * memory allocations. */ 307e28a4053SRui Paulo if (message_length > 65536) { 308e28a4053SRui Paulo wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size" 309e28a4053SRui Paulo " over 64 kB)"); 310e28a4053SRui Paulo return -1; 311e28a4053SRui Paulo } 312e28a4053SRui Paulo 31343f13beaSColin Percival if (len > message_length) { 31443f13beaSColin Percival wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in " 31543f13beaSColin Percival "first fragment of frame (TLS Message " 31643f13beaSColin Percival "Length %d bytes)", 31743f13beaSColin Percival (int) len, (int) message_length); 31843f13beaSColin Percival return -1; 31943f13beaSColin Percival } 32043f13beaSColin Percival 321e28a4053SRui Paulo data->tls_in = wpabuf_alloc(message_length); 322e28a4053SRui Paulo if (data->tls_in == NULL) { 323e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: No memory for message"); 324e28a4053SRui Paulo return -1; 325e28a4053SRui Paulo } 326e28a4053SRui Paulo wpabuf_put_data(data->tls_in, buf, len); 327e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first " 328e28a4053SRui Paulo "fragment, waiting for %lu bytes more", 329e28a4053SRui Paulo (unsigned long) len, 330e28a4053SRui Paulo (unsigned long) wpabuf_tailroom(data->tls_in)); 331e28a4053SRui Paulo } 332e28a4053SRui Paulo 333e28a4053SRui Paulo return 0; 334e28a4053SRui Paulo } 335e28a4053SRui Paulo 336e28a4053SRui Paulo 337e28a4053SRui Paulo int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) 338e28a4053SRui Paulo { 33985732ac8SCy Schubert char buf[20]; 34085732ac8SCy Schubert 341e28a4053SRui Paulo if (data->tls_out) { 342e28a4053SRui Paulo /* This should not happen.. */ 343e28a4053SRui Paulo wpa_printf(MSG_INFO, "SSL: pending tls_out data when " 344e28a4053SRui Paulo "processing new message"); 345e28a4053SRui Paulo wpabuf_free(data->tls_out); 346e28a4053SRui Paulo WPA_ASSERT(data->tls_out == NULL); 347e28a4053SRui Paulo } 348e28a4053SRui Paulo 349c1d255d3SCy Schubert data->tls_out = tls_connection_server_handshake(sm->cfg->ssl_ctx, 350e28a4053SRui Paulo data->conn, 351e28a4053SRui Paulo data->tls_in, NULL); 352e28a4053SRui Paulo if (data->tls_out == NULL) { 353e28a4053SRui Paulo wpa_printf(MSG_INFO, "SSL: TLS processing failed"); 354e28a4053SRui Paulo return -1; 355e28a4053SRui Paulo } 356c1d255d3SCy Schubert if (tls_connection_get_failed(sm->cfg->ssl_ctx, data->conn)) { 357e28a4053SRui Paulo /* TLS processing has failed - return error */ 358e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " 359e28a4053SRui Paulo "report error"); 360e28a4053SRui Paulo return -1; 361e28a4053SRui Paulo } 362e28a4053SRui Paulo 363c1d255d3SCy Schubert if (tls_get_version(sm->cfg->ssl_ctx, data->conn, 364c1d255d3SCy Schubert buf, sizeof(buf)) == 0) { 36585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf); 36685732ac8SCy Schubert data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0; 36785732ac8SCy Schubert } 36885732ac8SCy Schubert 36985732ac8SCy Schubert if (!sm->serial_num && 370c1d255d3SCy Schubert tls_connection_established(sm->cfg->ssl_ctx, data->conn)) 371c1d255d3SCy Schubert sm->serial_num = tls_connection_peer_serial_num( 372c1d255d3SCy Schubert sm->cfg->ssl_ctx, data->conn); 373c1d255d3SCy Schubert 374c1d255d3SCy Schubert /* 375*a90b9d01SCy Schubert * RFC 9190 Section 2.5 376c1d255d3SCy Schubert * 377c1d255d3SCy Schubert * We need to signal the other end that TLS negotiation is done. We 378c1d255d3SCy Schubert * can't send a zero-length application data message, so we send 379c1d255d3SCy Schubert * application data which is one byte of zero. 380c1d255d3SCy Schubert * 381c1d255d3SCy Schubert * Note this is only done for when there is no application data to be 382*a90b9d01SCy Schubert * sent. So this is done always for EAP-TLS but notably not for PEAP 383c1d255d3SCy Schubert * even on resumption. 384c1d255d3SCy Schubert */ 385c1d255d3SCy Schubert if (data->tls_v13 && 386c1d255d3SCy Schubert tls_connection_established(sm->cfg->ssl_ctx, data->conn)) { 387c1d255d3SCy Schubert struct wpabuf *plain, *encr; 388c1d255d3SCy Schubert 389c1d255d3SCy Schubert switch (sm->currentMethod) { 390c1d255d3SCy Schubert case EAP_TYPE_PEAP: 391c1d255d3SCy Schubert break; 392c1d255d3SCy Schubert default: 393c1d255d3SCy Schubert if (!tls_connection_resumed(sm->cfg->ssl_ctx, 394c1d255d3SCy Schubert data->conn)) 395c1d255d3SCy Schubert break; 396c1d255d3SCy Schubert /* fallthrough */ 397c1d255d3SCy Schubert case EAP_TYPE_TLS: 398*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 399*a90b9d01SCy Schubert if (data->skip_prot_success) { 400*a90b9d01SCy Schubert wpa_printf(MSG_INFO, 401*a90b9d01SCy Schubert "TESTING: Do not send protected success indication"); 402*a90b9d01SCy Schubert break; 403*a90b9d01SCy Schubert } 404*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 405c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 406*a90b9d01SCy Schubert "EAP-TLS: Send protected success indication (appl data 0x00)"); 407c1d255d3SCy Schubert 408c1d255d3SCy Schubert plain = wpabuf_alloc(1); 409c1d255d3SCy Schubert if (!plain) 410c1d255d3SCy Schubert return -1; 411c1d255d3SCy Schubert wpabuf_put_u8(plain, 0); 412c1d255d3SCy Schubert encr = eap_server_tls_encrypt(sm, data, plain); 413c1d255d3SCy Schubert wpabuf_free(plain); 414c1d255d3SCy Schubert if (!encr) 415c1d255d3SCy Schubert return -1; 416c1d255d3SCy Schubert if (wpabuf_resize(&data->tls_out, wpabuf_len(encr)) < 0) 417c1d255d3SCy Schubert { 418c1d255d3SCy Schubert wpa_printf(MSG_INFO, 419c1d255d3SCy Schubert "EAP-TLS: Failed to resize output buffer"); 420c1d255d3SCy Schubert wpabuf_free(encr); 421c1d255d3SCy Schubert return -1; 422c1d255d3SCy Schubert } 423c1d255d3SCy Schubert wpabuf_put_buf(data->tls_out, encr); 424c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, 425c1d255d3SCy Schubert "EAP-TLS: Data appended to the message", 426c1d255d3SCy Schubert encr); 427c1d255d3SCy Schubert wpabuf_free(encr); 428c1d255d3SCy Schubert } 429c1d255d3SCy Schubert } 43085732ac8SCy Schubert 431e28a4053SRui Paulo return 0; 432e28a4053SRui Paulo } 433e28a4053SRui Paulo 434e28a4053SRui Paulo 435e28a4053SRui Paulo static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags, 436e28a4053SRui Paulo const u8 **pos, size_t *left) 437e28a4053SRui Paulo { 438e28a4053SRui Paulo unsigned int tls_msg_len = 0; 439e28a4053SRui Paulo const u8 *end = *pos + *left; 440e28a4053SRui Paulo 441206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "SSL: Received data", *pos, *left); 442206b73d0SCy Schubert 443e28a4053SRui Paulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { 444e28a4053SRui Paulo if (*left < 4) { 445e28a4053SRui Paulo wpa_printf(MSG_INFO, "SSL: Short frame with TLS " 446e28a4053SRui Paulo "length"); 447e28a4053SRui Paulo return -1; 448e28a4053SRui Paulo } 449e28a4053SRui Paulo tls_msg_len = WPA_GET_BE32(*pos); 450e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", 451e28a4053SRui Paulo tls_msg_len); 452e28a4053SRui Paulo *pos += 4; 453e28a4053SRui Paulo *left -= 4; 454f05cddf9SRui Paulo 455f05cddf9SRui Paulo if (*left > tls_msg_len) { 456f05cddf9SRui Paulo wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " 457f05cddf9SRui Paulo "bytes) smaller than this fragment (%d " 458f05cddf9SRui Paulo "bytes)", (int) tls_msg_len, (int) *left); 459f05cddf9SRui Paulo return -1; 460f05cddf9SRui Paulo } 461e28a4053SRui Paulo } 462e28a4053SRui Paulo 463e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x " 464e28a4053SRui Paulo "Message Length %u", flags, tls_msg_len); 465e28a4053SRui Paulo 466e28a4053SRui Paulo if (data->state == WAIT_FRAG_ACK) { 467e28a4053SRui Paulo if (*left != 0) { 468e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in " 469e28a4053SRui Paulo "WAIT_FRAG_ACK state"); 470e28a4053SRui Paulo return -1; 471e28a4053SRui Paulo } 472e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged"); 473e28a4053SRui Paulo return 1; 474e28a4053SRui Paulo } 475e28a4053SRui Paulo 476e28a4053SRui Paulo if (data->tls_in && 477e28a4053SRui Paulo eap_server_tls_process_cont(data, *pos, end - *pos) < 0) 478e28a4053SRui Paulo return -1; 479e28a4053SRui Paulo 480e28a4053SRui Paulo if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) { 481e28a4053SRui Paulo if (eap_server_tls_process_fragment(data, flags, tls_msg_len, 482e28a4053SRui Paulo *pos, end - *pos) < 0) 483e28a4053SRui Paulo return -1; 484e28a4053SRui Paulo 485e28a4053SRui Paulo data->state = FRAG_ACK; 486e28a4053SRui Paulo return 1; 487e28a4053SRui Paulo } 488e28a4053SRui Paulo 489e28a4053SRui Paulo if (data->state == FRAG_ACK) { 490e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: All fragments received"); 491e28a4053SRui Paulo data->state = MSG; 492e28a4053SRui Paulo } 493e28a4053SRui Paulo 494e28a4053SRui Paulo if (data->tls_in == NULL) { 495e28a4053SRui Paulo /* Wrap unfragmented messages as wpabuf without extra copy */ 496e28a4053SRui Paulo wpabuf_set(&data->tmpbuf, *pos, end - *pos); 497e28a4053SRui Paulo data->tls_in = &data->tmpbuf; 498e28a4053SRui Paulo } 499e28a4053SRui Paulo 500e28a4053SRui Paulo return 0; 501e28a4053SRui Paulo } 502e28a4053SRui Paulo 503e28a4053SRui Paulo 504e28a4053SRui Paulo static void eap_server_tls_free_in_buf(struct eap_ssl_data *data) 505e28a4053SRui Paulo { 506e28a4053SRui Paulo if (data->tls_in != &data->tmpbuf) 507e28a4053SRui Paulo wpabuf_free(data->tls_in); 508e28a4053SRui Paulo data->tls_in = NULL; 509e28a4053SRui Paulo } 510e28a4053SRui Paulo 511e28a4053SRui Paulo 512e28a4053SRui Paulo struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, 513e28a4053SRui Paulo struct eap_ssl_data *data, 514e28a4053SRui Paulo const struct wpabuf *plain) 515e28a4053SRui Paulo { 516e28a4053SRui Paulo struct wpabuf *buf; 517e28a4053SRui Paulo 518c1d255d3SCy Schubert buf = tls_connection_encrypt(sm->cfg->ssl_ctx, data->conn, plain); 519e28a4053SRui Paulo if (buf == NULL) { 520e28a4053SRui Paulo wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data"); 521e28a4053SRui Paulo return NULL; 522e28a4053SRui Paulo } 523e28a4053SRui Paulo 524e28a4053SRui Paulo return buf; 525e28a4053SRui Paulo } 526e28a4053SRui Paulo 527e28a4053SRui Paulo 528e28a4053SRui Paulo int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, 529e28a4053SRui Paulo struct wpabuf *respData, void *priv, int eap_type, 530e28a4053SRui Paulo int (*proc_version)(struct eap_sm *sm, void *priv, 531e28a4053SRui Paulo int peer_version), 532e28a4053SRui Paulo void (*proc_msg)(struct eap_sm *sm, void *priv, 533e28a4053SRui Paulo const struct wpabuf *respData)) 534e28a4053SRui Paulo { 535e28a4053SRui Paulo const u8 *pos; 536e28a4053SRui Paulo u8 flags; 537e28a4053SRui Paulo size_t left; 538e28a4053SRui Paulo int ret, res = 0; 539e28a4053SRui Paulo 540f05cddf9SRui Paulo if (eap_type == EAP_UNAUTH_TLS_TYPE) 541f05cddf9SRui Paulo pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, 542f05cddf9SRui Paulo EAP_VENDOR_TYPE_UNAUTH_TLS, respData, 543f05cddf9SRui Paulo &left); 5445b9c547cSRui Paulo else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE) 5455b9c547cSRui Paulo pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW, 5465b9c547cSRui Paulo EAP_VENDOR_WFA_UNAUTH_TLS, respData, 5475b9c547cSRui Paulo &left); 548f05cddf9SRui Paulo else 549f05cddf9SRui Paulo pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, 550f05cddf9SRui Paulo &left); 551e28a4053SRui Paulo if (pos == NULL || left < 1) 552e28a4053SRui Paulo return 0; /* Should not happen - frame already validated */ 553e28a4053SRui Paulo flags = *pos++; 554e28a4053SRui Paulo left--; 555e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x", 556e28a4053SRui Paulo (unsigned long) wpabuf_len(respData), flags); 557e28a4053SRui Paulo 558e28a4053SRui Paulo if (proc_version && 559e28a4053SRui Paulo proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0) 560e28a4053SRui Paulo return -1; 561e28a4053SRui Paulo 562e28a4053SRui Paulo ret = eap_server_tls_reassemble(data, flags, &pos, &left); 563e28a4053SRui Paulo if (ret < 0) { 564e28a4053SRui Paulo res = -1; 565e28a4053SRui Paulo goto done; 566e28a4053SRui Paulo } else if (ret == 1) 567e28a4053SRui Paulo return 0; 568e28a4053SRui Paulo 569e28a4053SRui Paulo if (proc_msg) 570e28a4053SRui Paulo proc_msg(sm, priv, respData); 571e28a4053SRui Paulo 572c1d255d3SCy Schubert if (tls_connection_get_write_alerts(sm->cfg->ssl_ctx, data->conn) > 1) { 573e28a4053SRui Paulo wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in " 574e28a4053SRui Paulo "TLS processing"); 575e28a4053SRui Paulo res = -1; 576e28a4053SRui Paulo } 577e28a4053SRui Paulo 578e28a4053SRui Paulo done: 579e28a4053SRui Paulo eap_server_tls_free_in_buf(data); 580e28a4053SRui Paulo 581e28a4053SRui Paulo return res; 582e28a4053SRui Paulo } 583