1189251Ssam/* 2189251Ssam * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions 3252726Srpaulo * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12214734Srpaulo#include "crypto/sha1.h" 13214734Srpaulo#include "crypto/tls.h" 14189251Ssam#include "eap_i.h" 15189251Ssam#include "eap_tls_common.h" 16189251Ssam#include "eap_config.h" 17189251Ssam 18189251Ssam 19252726Srpaulostatic struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, 20252726Srpaulo u8 code, u8 identifier) 21252726Srpaulo{ 22252726Srpaulo if (type == EAP_UNAUTH_TLS_TYPE) 23252726Srpaulo return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, 24252726Srpaulo EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, 25252726Srpaulo code, identifier); 26252726Srpaulo return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, 27252726Srpaulo identifier); 28252726Srpaulo} 29252726Srpaulo 30252726Srpaulo 31189251Ssamstatic int eap_tls_check_blob(struct eap_sm *sm, const char **name, 32189251Ssam const u8 **data, size_t *data_len) 33189251Ssam{ 34189251Ssam const struct wpa_config_blob *blob; 35189251Ssam 36189251Ssam if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0) 37189251Ssam return 0; 38189251Ssam 39189251Ssam blob = eap_get_config_blob(sm, *name + 7); 40189251Ssam if (blob == NULL) { 41189251Ssam wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not " 42189251Ssam "found", __func__, *name + 7); 43189251Ssam return -1; 44189251Ssam } 45189251Ssam 46189251Ssam *name = NULL; 47189251Ssam *data = blob->data; 48189251Ssam *data_len = blob->len; 49189251Ssam 50189251Ssam return 0; 51189251Ssam} 52189251Ssam 53189251Ssam 54209158Srpaulostatic void eap_tls_params_flags(struct tls_connection_params *params, 55209158Srpaulo const char *txt) 56209158Srpaulo{ 57209158Srpaulo if (txt == NULL) 58209158Srpaulo return; 59209158Srpaulo if (os_strstr(txt, "tls_allow_md5=1")) 60209158Srpaulo params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5; 61209158Srpaulo if (os_strstr(txt, "tls_disable_time_checks=1")) 62209158Srpaulo params->flags |= TLS_CONN_DISABLE_TIME_CHECKS; 63252726Srpaulo if (os_strstr(txt, "tls_disable_session_ticket=1")) 64252726Srpaulo params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; 65252726Srpaulo if (os_strstr(txt, "tls_disable_session_ticket=0")) 66252726Srpaulo params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET; 67209158Srpaulo} 68209158Srpaulo 69209158Srpaulo 70189251Ssamstatic void eap_tls_params_from_conf1(struct tls_connection_params *params, 71189251Ssam struct eap_peer_config *config) 72189251Ssam{ 73189251Ssam params->ca_cert = (char *) config->ca_cert; 74189251Ssam params->ca_path = (char *) config->ca_path; 75189251Ssam params->client_cert = (char *) config->client_cert; 76189251Ssam params->private_key = (char *) config->private_key; 77189251Ssam params->private_key_passwd = (char *) config->private_key_passwd; 78189251Ssam params->dh_file = (char *) config->dh_file; 79189251Ssam params->subject_match = (char *) config->subject_match; 80189251Ssam params->altsubject_match = (char *) config->altsubject_match; 81189251Ssam params->engine = config->engine; 82189251Ssam params->engine_id = config->engine_id; 83189251Ssam params->pin = config->pin; 84189251Ssam params->key_id = config->key_id; 85189251Ssam params->cert_id = config->cert_id; 86189251Ssam params->ca_cert_id = config->ca_cert_id; 87209158Srpaulo eap_tls_params_flags(params, config->phase1); 88189251Ssam} 89189251Ssam 90189251Ssam 91189251Ssamstatic void eap_tls_params_from_conf2(struct tls_connection_params *params, 92189251Ssam struct eap_peer_config *config) 93189251Ssam{ 94189251Ssam params->ca_cert = (char *) config->ca_cert2; 95189251Ssam params->ca_path = (char *) config->ca_path2; 96189251Ssam params->client_cert = (char *) config->client_cert2; 97189251Ssam params->private_key = (char *) config->private_key2; 98189251Ssam params->private_key_passwd = (char *) config->private_key2_passwd; 99189251Ssam params->dh_file = (char *) config->dh_file2; 100189251Ssam params->subject_match = (char *) config->subject_match2; 101189251Ssam params->altsubject_match = (char *) config->altsubject_match2; 102189251Ssam params->engine = config->engine2; 103189251Ssam params->engine_id = config->engine2_id; 104189251Ssam params->pin = config->pin2; 105189251Ssam params->key_id = config->key2_id; 106189251Ssam params->cert_id = config->cert2_id; 107189251Ssam params->ca_cert_id = config->ca_cert2_id; 108209158Srpaulo eap_tls_params_flags(params, config->phase2); 109189251Ssam} 110189251Ssam 111189251Ssam 112189251Ssamstatic int eap_tls_params_from_conf(struct eap_sm *sm, 113189251Ssam struct eap_ssl_data *data, 114189251Ssam struct tls_connection_params *params, 115189251Ssam struct eap_peer_config *config, int phase2) 116189251Ssam{ 117189251Ssam os_memset(params, 0, sizeof(*params)); 118252726Srpaulo if (sm->workaround && data->eap_type != EAP_TYPE_FAST) { 119252726Srpaulo /* 120252726Srpaulo * Some deployed authentication servers seem to be unable to 121252726Srpaulo * handle the TLS Session Ticket extension (they are supposed 122252726Srpaulo * to ignore unrecognized TLS extensions, but end up rejecting 123252726Srpaulo * the ClientHello instead). As a workaround, disable use of 124252726Srpaulo * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and 125252726Srpaulo * EAP-TTLS (EAP-FAST uses session ticket, so any server that 126252726Srpaulo * supports EAP-FAST does not need this workaround). 127252726Srpaulo */ 128252726Srpaulo params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; 129252726Srpaulo } 130189251Ssam if (phase2) { 131189251Ssam wpa_printf(MSG_DEBUG, "TLS: using phase2 config options"); 132189251Ssam eap_tls_params_from_conf2(params, config); 133189251Ssam } else { 134189251Ssam wpa_printf(MSG_DEBUG, "TLS: using phase1 config options"); 135189251Ssam eap_tls_params_from_conf1(params, config); 136189251Ssam } 137189251Ssam 138189251Ssam /* 139189251Ssam * Use blob data, if available. Otherwise, leave reference to external 140189251Ssam * file as-is. 141189251Ssam */ 142189251Ssam if (eap_tls_check_blob(sm, ¶ms->ca_cert, ¶ms->ca_cert_blob, 143189251Ssam ¶ms->ca_cert_blob_len) || 144189251Ssam eap_tls_check_blob(sm, ¶ms->client_cert, 145189251Ssam ¶ms->client_cert_blob, 146189251Ssam ¶ms->client_cert_blob_len) || 147189251Ssam eap_tls_check_blob(sm, ¶ms->private_key, 148189251Ssam ¶ms->private_key_blob, 149189251Ssam ¶ms->private_key_blob_len) || 150189251Ssam eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, 151189251Ssam ¶ms->dh_blob_len)) { 152189251Ssam wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); 153189251Ssam return -1; 154189251Ssam } 155189251Ssam 156189251Ssam return 0; 157189251Ssam} 158189251Ssam 159189251Ssam 160189251Ssamstatic int eap_tls_init_connection(struct eap_sm *sm, 161189251Ssam struct eap_ssl_data *data, 162189251Ssam struct eap_peer_config *config, 163189251Ssam struct tls_connection_params *params) 164189251Ssam{ 165189251Ssam int res; 166189251Ssam 167252726Srpaulo data->conn = tls_connection_init(data->ssl_ctx); 168189251Ssam if (data->conn == NULL) { 169189251Ssam wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " 170189251Ssam "connection"); 171189251Ssam return -1; 172189251Ssam } 173189251Ssam 174252726Srpaulo res = tls_connection_set_params(data->ssl_ctx, data->conn, params); 175189251Ssam if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) { 176189251Ssam /* 177189251Ssam * At this point with the pkcs11 engine the PIN might be wrong. 178189251Ssam * We reset the PIN in the configuration to be sure to not use 179189251Ssam * it again and the calling function must request a new one. 180189251Ssam */ 181189251Ssam os_free(config->pin); 182189251Ssam config->pin = NULL; 183189251Ssam } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) { 184189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load private key"); 185189251Ssam /* 186189251Ssam * We do not know exactly but maybe the PIN was wrong, 187189251Ssam * so ask for a new one. 188189251Ssam */ 189189251Ssam os_free(config->pin); 190189251Ssam config->pin = NULL; 191189251Ssam eap_sm_request_pin(sm); 192189251Ssam sm->ignore = TRUE; 193252726Srpaulo tls_connection_deinit(data->ssl_ctx, data->conn); 194214734Srpaulo data->conn = NULL; 195189251Ssam return -1; 196189251Ssam } else if (res) { 197189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection " 198189251Ssam "parameters"); 199252726Srpaulo tls_connection_deinit(data->ssl_ctx, data->conn); 200214734Srpaulo data->conn = NULL; 201189251Ssam return -1; 202189251Ssam } 203189251Ssam 204189251Ssam return 0; 205189251Ssam} 206189251Ssam 207189251Ssam 208189251Ssam/** 209189251Ssam * eap_peer_tls_ssl_init - Initialize shared TLS functionality 210189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 211189251Ssam * @data: Data for TLS processing 212189251Ssam * @config: Pointer to the network configuration 213252726Srpaulo * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) 214189251Ssam * Returns: 0 on success, -1 on failure 215189251Ssam * 216189251Ssam * This function is used to initialize shared TLS functionality for EAP-TLS, 217189251Ssam * EAP-PEAP, EAP-TTLS, and EAP-FAST. 218189251Ssam */ 219189251Ssamint eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, 220252726Srpaulo struct eap_peer_config *config, u8 eap_type) 221189251Ssam{ 222189251Ssam struct tls_connection_params params; 223189251Ssam 224189251Ssam if (config == NULL) 225189251Ssam return -1; 226189251Ssam 227189251Ssam data->eap = sm; 228252726Srpaulo data->eap_type = eap_type; 229189251Ssam data->phase2 = sm->init_phase2; 230252726Srpaulo data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : 231252726Srpaulo sm->ssl_ctx; 232189251Ssam if (eap_tls_params_from_conf(sm, data, ¶ms, config, data->phase2) < 233189251Ssam 0) 234189251Ssam return -1; 235189251Ssam 236189251Ssam if (eap_tls_init_connection(sm, data, config, ¶ms) < 0) 237189251Ssam return -1; 238189251Ssam 239189251Ssam data->tls_out_limit = config->fragment_size; 240189251Ssam if (data->phase2) { 241189251Ssam /* Limit the fragment size in the inner TLS authentication 242189251Ssam * since the outer authentication with EAP-PEAP does not yet 243189251Ssam * support fragmentation */ 244189251Ssam if (data->tls_out_limit > 100) 245189251Ssam data->tls_out_limit -= 100; 246189251Ssam } 247189251Ssam 248189251Ssam if (config->phase1 && 249189251Ssam os_strstr(config->phase1, "include_tls_length=1")) { 250189251Ssam wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in " 251189251Ssam "unfragmented packets"); 252189251Ssam data->include_tls_length = 1; 253189251Ssam } 254189251Ssam 255189251Ssam return 0; 256189251Ssam} 257189251Ssam 258189251Ssam 259189251Ssam/** 260189251Ssam * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality 261189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 262189251Ssam * @data: Data for TLS processing 263189251Ssam * 264189251Ssam * This function deinitializes shared TLS functionality that was initialized 265189251Ssam * with eap_peer_tls_ssl_init(). 266189251Ssam */ 267189251Ssamvoid eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) 268189251Ssam{ 269252726Srpaulo tls_connection_deinit(data->ssl_ctx, data->conn); 270189251Ssam eap_peer_tls_reset_input(data); 271189251Ssam eap_peer_tls_reset_output(data); 272189251Ssam} 273189251Ssam 274189251Ssam 275189251Ssam/** 276189251Ssam * eap_peer_tls_derive_key - Derive a key based on TLS session data 277189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 278189251Ssam * @data: Data for TLS processing 279189251Ssam * @label: Label string for deriving the keys, e.g., "client EAP encryption" 280189251Ssam * @len: Length of the key material to generate (usually 64 for MSK) 281189251Ssam * Returns: Pointer to allocated key on success or %NULL on failure 282189251Ssam * 283189251Ssam * This function uses TLS-PRF to generate pseudo-random data based on the TLS 284189251Ssam * session data (client/server random and master key). Each key type may use a 285189251Ssam * different label to bind the key usage into the generated material. 286189251Ssam * 287189251Ssam * The caller is responsible for freeing the returned buffer. 288189251Ssam */ 289189251Ssamu8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, 290189251Ssam const char *label, size_t len) 291189251Ssam{ 292252726Srpaulo#ifndef CONFIG_FIPS 293189251Ssam struct tls_keys keys; 294252726Srpaulo#endif /* CONFIG_FIPS */ 295189251Ssam u8 *rnd = NULL, *out; 296189251Ssam 297189251Ssam out = os_malloc(len); 298189251Ssam if (out == NULL) 299189251Ssam return NULL; 300189251Ssam 301189251Ssam /* First, try to use TLS library function for PRF, if available. */ 302252726Srpaulo if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len) 303252726Srpaulo == 0) 304189251Ssam return out; 305189251Ssam 306252726Srpaulo#ifndef CONFIG_FIPS 307189251Ssam /* 308189251Ssam * TLS library did not support key generation, so get the needed TLS 309189251Ssam * session parameters and use an internal implementation of TLS PRF to 310189251Ssam * derive the key. 311189251Ssam */ 312252726Srpaulo if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys)) 313189251Ssam goto fail; 314189251Ssam 315189251Ssam if (keys.client_random == NULL || keys.server_random == NULL || 316189251Ssam keys.master_key == NULL) 317189251Ssam goto fail; 318189251Ssam 319189251Ssam rnd = os_malloc(keys.client_random_len + keys.server_random_len); 320189251Ssam if (rnd == NULL) 321189251Ssam goto fail; 322189251Ssam os_memcpy(rnd, keys.client_random, keys.client_random_len); 323189251Ssam os_memcpy(rnd + keys.client_random_len, keys.server_random, 324189251Ssam keys.server_random_len); 325189251Ssam 326252726Srpaulo if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, 327252726Srpaulo label, rnd, keys.client_random_len + 328252726Srpaulo keys.server_random_len, out, len)) 329189251Ssam goto fail; 330189251Ssam 331189251Ssam os_free(rnd); 332189251Ssam return out; 333189251Ssam 334189251Ssamfail: 335252726Srpaulo#endif /* CONFIG_FIPS */ 336189251Ssam os_free(out); 337189251Ssam os_free(rnd); 338189251Ssam return NULL; 339189251Ssam} 340189251Ssam 341189251Ssam 342189251Ssam/** 343189251Ssam * eap_peer_tls_reassemble_fragment - Reassemble a received fragment 344189251Ssam * @data: Data for TLS processing 345189251Ssam * @in_data: Next incoming TLS segment 346189251Ssam * Returns: 0 on success, 1 if more data is needed for the full message, or 347189251Ssam * -1 on error 348189251Ssam */ 349189251Ssamstatic int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, 350214734Srpaulo const struct wpabuf *in_data) 351189251Ssam{ 352214734Srpaulo size_t tls_in_len, in_len; 353189251Ssam 354214734Srpaulo tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0; 355214734Srpaulo in_len = in_data ? wpabuf_len(in_data) : 0; 356214734Srpaulo 357214734Srpaulo if (tls_in_len + in_len == 0) { 358189251Ssam /* No message data received?! */ 359189251Ssam wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: " 360189251Ssam "tls_in_left=%lu tls_in_len=%lu in_len=%lu", 361189251Ssam (unsigned long) data->tls_in_left, 362214734Srpaulo (unsigned long) tls_in_len, 363189251Ssam (unsigned long) in_len); 364189251Ssam eap_peer_tls_reset_input(data); 365189251Ssam return -1; 366189251Ssam } 367189251Ssam 368214734Srpaulo if (tls_in_len + in_len > 65536) { 369189251Ssam /* 370189251Ssam * Limit length to avoid rogue servers from causing large 371189251Ssam * memory allocations. 372189251Ssam */ 373189251Ssam wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over " 374189251Ssam "64 kB)"); 375189251Ssam eap_peer_tls_reset_input(data); 376189251Ssam return -1; 377189251Ssam } 378189251Ssam 379189251Ssam if (in_len > data->tls_in_left) { 380189251Ssam /* Sender is doing something odd - reject message */ 381189251Ssam wpa_printf(MSG_INFO, "SSL: more data than TLS message length " 382189251Ssam "indicated"); 383189251Ssam eap_peer_tls_reset_input(data); 384189251Ssam return -1; 385189251Ssam } 386189251Ssam 387214734Srpaulo if (wpabuf_resize(&data->tls_in, in_len) < 0) { 388189251Ssam wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS " 389189251Ssam "data"); 390189251Ssam eap_peer_tls_reset_input(data); 391189251Ssam return -1; 392189251Ssam } 393252726Srpaulo if (in_data) 394252726Srpaulo wpabuf_put_buf(data->tls_in, in_data); 395189251Ssam data->tls_in_left -= in_len; 396189251Ssam 397189251Ssam if (data->tls_in_left > 0) { 398189251Ssam wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input " 399189251Ssam "data", (unsigned long) data->tls_in_left); 400189251Ssam return 1; 401189251Ssam } 402189251Ssam 403189251Ssam return 0; 404189251Ssam} 405189251Ssam 406189251Ssam 407189251Ssam/** 408189251Ssam * eap_peer_tls_data_reassemble - Reassemble TLS data 409189251Ssam * @data: Data for TLS processing 410189251Ssam * @in_data: Next incoming TLS segment 411189251Ssam * @need_more_input: Variable for returning whether more input data is needed 412189251Ssam * to reassemble this TLS packet 413189251Ssam * Returns: Pointer to output data, %NULL on error or when more data is needed 414189251Ssam * for the full message (in which case, *need_more_input is also set to 1). 415189251Ssam * 416189251Ssam * This function reassembles TLS fragments. Caller must not free the returned 417189251Ssam * data buffer since an internal pointer to it is maintained. 418189251Ssam */ 419214734Srpaulostatic const struct wpabuf * eap_peer_tls_data_reassemble( 420214734Srpaulo struct eap_ssl_data *data, const struct wpabuf *in_data, 421214734Srpaulo int *need_more_input) 422189251Ssam{ 423189251Ssam *need_more_input = 0; 424189251Ssam 425214734Srpaulo if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) { 426189251Ssam /* Message has fragments */ 427214734Srpaulo int res = eap_peer_tls_reassemble_fragment(data, in_data); 428189251Ssam if (res) { 429189251Ssam if (res == 1) 430189251Ssam *need_more_input = 1; 431189251Ssam return NULL; 432189251Ssam } 433189251Ssam 434189251Ssam /* Message is now fully reassembled. */ 435189251Ssam } else { 436189251Ssam /* No fragments in this message, so just make a copy of it. */ 437189251Ssam data->tls_in_left = 0; 438214734Srpaulo data->tls_in = wpabuf_dup(in_data); 439189251Ssam if (data->tls_in == NULL) 440189251Ssam return NULL; 441189251Ssam } 442189251Ssam 443189251Ssam return data->tls_in; 444189251Ssam} 445189251Ssam 446189251Ssam 447189251Ssam/** 448189251Ssam * eap_tls_process_input - Process incoming TLS message 449189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 450189251Ssam * @data: Data for TLS processing 451189251Ssam * @in_data: Message received from the server 452189251Ssam * @in_len: Length of in_data 453189251Ssam * @out_data: Buffer for returning a pointer to application data (if available) 454189251Ssam * Returns: 0 on success, 1 if more input data is needed, 2 if application data 455189251Ssam * is available, -1 on failure 456189251Ssam */ 457189251Ssamstatic int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, 458189251Ssam const u8 *in_data, size_t in_len, 459189251Ssam struct wpabuf **out_data) 460189251Ssam{ 461214734Srpaulo const struct wpabuf *msg; 462189251Ssam int need_more_input; 463214734Srpaulo struct wpabuf *appl_data; 464214734Srpaulo struct wpabuf buf; 465189251Ssam 466214734Srpaulo wpabuf_set(&buf, in_data, in_len); 467214734Srpaulo msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input); 468189251Ssam if (msg == NULL) 469189251Ssam return need_more_input ? 1 : -1; 470189251Ssam 471189251Ssam /* Full TLS message reassembled - continue handshake processing */ 472189251Ssam if (data->tls_out) { 473189251Ssam /* This should not happen.. */ 474189251Ssam wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending " 475189251Ssam "tls_out data even though tls_out_len = 0"); 476214734Srpaulo wpabuf_free(data->tls_out); 477189251Ssam WPA_ASSERT(data->tls_out == NULL); 478189251Ssam } 479189251Ssam appl_data = NULL; 480252726Srpaulo data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn, 481214734Srpaulo msg, &appl_data); 482189251Ssam 483189251Ssam eap_peer_tls_reset_input(data); 484189251Ssam 485189251Ssam if (appl_data && 486252726Srpaulo tls_connection_established(data->ssl_ctx, data->conn) && 487252726Srpaulo !tls_connection_get_failed(data->ssl_ctx, data->conn)) { 488214734Srpaulo wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data", 489214734Srpaulo appl_data); 490214734Srpaulo *out_data = appl_data; 491189251Ssam return 2; 492189251Ssam } 493189251Ssam 494214734Srpaulo wpabuf_free(appl_data); 495189251Ssam 496189251Ssam return 0; 497189251Ssam} 498189251Ssam 499189251Ssam 500189251Ssam/** 501189251Ssam * eap_tls_process_output - Process outgoing TLS message 502189251Ssam * @data: Data for TLS processing 503189251Ssam * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 504189251Ssam * @peap_version: Version number for EAP-PEAP/TTLS 505189251Ssam * @id: EAP identifier for the response 506189251Ssam * @ret: Return value to use on success 507189251Ssam * @out_data: Buffer for returning the allocated output buffer 508189251Ssam * Returns: ret (0 or 1) on success, -1 on failure 509189251Ssam */ 510189251Ssamstatic int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, 511189251Ssam int peap_version, u8 id, int ret, 512189251Ssam struct wpabuf **out_data) 513189251Ssam{ 514189251Ssam size_t len; 515189251Ssam u8 *flags; 516189251Ssam int more_fragments, length_included; 517214734Srpaulo 518214734Srpaulo if (data->tls_out == NULL) 519214734Srpaulo return -1; 520214734Srpaulo len = wpabuf_len(data->tls_out) - data->tls_out_pos; 521189251Ssam wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " 522189251Ssam "%lu bytes)", 523214734Srpaulo (unsigned long) len, 524214734Srpaulo (unsigned long) wpabuf_len(data->tls_out)); 525189251Ssam 526189251Ssam /* 527189251Ssam * Limit outgoing message to the configured maximum size. Fragment 528189251Ssam * message if needed. 529189251Ssam */ 530189251Ssam if (len > data->tls_out_limit) { 531189251Ssam more_fragments = 1; 532189251Ssam len = data->tls_out_limit; 533189251Ssam wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments " 534189251Ssam "will follow", (unsigned long) len); 535189251Ssam } else 536189251Ssam more_fragments = 0; 537189251Ssam 538189251Ssam length_included = data->tls_out_pos == 0 && 539214734Srpaulo (wpabuf_len(data->tls_out) > data->tls_out_limit || 540189251Ssam data->include_tls_length); 541189251Ssam if (!length_included && 542189251Ssam eap_type == EAP_TYPE_PEAP && peap_version == 0 && 543189251Ssam !tls_connection_established(data->eap->ssl_ctx, data->conn)) { 544189251Ssam /* 545189251Ssam * Windows Server 2008 NPS really wants to have the TLS Message 546189251Ssam * length included in phase 0 even for unfragmented frames or 547189251Ssam * it will get very confused with Compound MAC calculation and 548189251Ssam * Outer TLVs. 549189251Ssam */ 550189251Ssam length_included = 1; 551189251Ssam } 552189251Ssam 553252726Srpaulo *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len, 554252726Srpaulo EAP_CODE_RESPONSE, id); 555189251Ssam if (*out_data == NULL) 556189251Ssam return -1; 557189251Ssam 558189251Ssam flags = wpabuf_put(*out_data, 1); 559189251Ssam *flags = peap_version; 560189251Ssam if (more_fragments) 561189251Ssam *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; 562189251Ssam if (length_included) { 563189251Ssam *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; 564214734Srpaulo wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out)); 565189251Ssam } 566189251Ssam 567214734Srpaulo wpabuf_put_data(*out_data, 568214734Srpaulo wpabuf_head_u8(data->tls_out) + data->tls_out_pos, 569214734Srpaulo len); 570189251Ssam data->tls_out_pos += len; 571189251Ssam 572189251Ssam if (!more_fragments) 573189251Ssam eap_peer_tls_reset_output(data); 574189251Ssam 575189251Ssam return ret; 576189251Ssam} 577189251Ssam 578189251Ssam 579189251Ssam/** 580189251Ssam * eap_peer_tls_process_helper - Process TLS handshake message 581189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 582189251Ssam * @data: Data for TLS processing 583189251Ssam * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 584189251Ssam * @peap_version: Version number for EAP-PEAP/TTLS 585189251Ssam * @id: EAP identifier for the response 586189251Ssam * @in_data: Message received from the server 587189251Ssam * @in_len: Length of in_data 588189251Ssam * @out_data: Buffer for returning a pointer to the response message 589189251Ssam * Returns: 0 on success, 1 if more input data is needed, 2 if application data 590189251Ssam * is available, or -1 on failure 591189251Ssam * 592189251Ssam * This function can be used to process TLS handshake messages. It reassembles 593189251Ssam * the received fragments and uses a TLS library to process the messages. The 594189251Ssam * response data from the TLS library is fragmented to suitable output messages 595189251Ssam * that the caller can send out. 596189251Ssam * 597189251Ssam * out_data is used to return the response message if the return value of this 598189251Ssam * function is 0, 2, or -1. In case of failure, the message is likely a TLS 599189251Ssam * alarm message. The caller is responsible for freeing the allocated buffer if 600189251Ssam * *out_data is not %NULL. 601189251Ssam * 602189251Ssam * This function is called for each received TLS message during the TLS 603189251Ssam * handshake after eap_peer_tls_process_init() call and possible processing of 604189251Ssam * TLS Flags field. Once the handshake has been completed, i.e., when 605189251Ssam * tls_connection_established() returns 1, EAP method specific decrypting of 606189251Ssam * the tunneled data is used. 607189251Ssam */ 608189251Ssamint eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, 609189251Ssam EapType eap_type, int peap_version, 610189251Ssam u8 id, const u8 *in_data, size_t in_len, 611189251Ssam struct wpabuf **out_data) 612189251Ssam{ 613189251Ssam int ret = 0; 614189251Ssam 615189251Ssam *out_data = NULL; 616189251Ssam 617214734Srpaulo if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 0) { 618189251Ssam wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output " 619189251Ssam "fragments are waiting to be sent out"); 620189251Ssam return -1; 621189251Ssam } 622189251Ssam 623214734Srpaulo if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { 624189251Ssam /* 625189251Ssam * No more data to send out - expect to receive more data from 626189251Ssam * the AS. 627189251Ssam */ 628189251Ssam int res = eap_tls_process_input(sm, data, in_data, in_len, 629189251Ssam out_data); 630189251Ssam if (res) { 631189251Ssam /* 632189251Ssam * Input processing failed (res = -1) or more data is 633189251Ssam * needed (res = 1). 634189251Ssam */ 635189251Ssam return res; 636189251Ssam } 637189251Ssam 638189251Ssam /* 639189251Ssam * The incoming message has been reassembled and processed. The 640189251Ssam * response was allocated into data->tls_out buffer. 641189251Ssam */ 642189251Ssam } 643189251Ssam 644189251Ssam if (data->tls_out == NULL) { 645189251Ssam /* 646189251Ssam * No outgoing fragments remaining from the previous message 647189251Ssam * and no new message generated. This indicates an error in TLS 648189251Ssam * processing. 649189251Ssam */ 650189251Ssam eap_peer_tls_reset_output(data); 651189251Ssam return -1; 652189251Ssam } 653189251Ssam 654252726Srpaulo if (tls_connection_get_failed(data->ssl_ctx, data->conn)) { 655189251Ssam /* TLS processing has failed - return error */ 656189251Ssam wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " 657189251Ssam "report error"); 658189251Ssam ret = -1; 659189251Ssam /* TODO: clean pin if engine used? */ 660189251Ssam } 661189251Ssam 662214734Srpaulo if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { 663189251Ssam /* 664189251Ssam * TLS negotiation should now be complete since all other cases 665189251Ssam * needing more data should have been caught above based on 666189251Ssam * the TLS Message Length field. 667189251Ssam */ 668189251Ssam wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); 669214734Srpaulo wpabuf_free(data->tls_out); 670189251Ssam data->tls_out = NULL; 671189251Ssam return 1; 672189251Ssam } 673189251Ssam 674189251Ssam /* Send the pending message (in fragments, if needed). */ 675189251Ssam return eap_tls_process_output(data, eap_type, peap_version, id, ret, 676189251Ssam out_data); 677189251Ssam} 678189251Ssam 679189251Ssam 680189251Ssam/** 681189251Ssam * eap_peer_tls_build_ack - Build a TLS ACK frame 682189251Ssam * @id: EAP identifier for the response 683189251Ssam * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 684189251Ssam * @peap_version: Version number for EAP-PEAP/TTLS 685189251Ssam * Returns: Pointer to the allocated ACK frame or %NULL on failure 686189251Ssam */ 687189251Ssamstruct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, 688189251Ssam int peap_version) 689189251Ssam{ 690189251Ssam struct wpabuf *resp; 691189251Ssam 692252726Srpaulo resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id); 693189251Ssam if (resp == NULL) 694189251Ssam return NULL; 695189251Ssam wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)", 696189251Ssam (int) eap_type, id, peap_version); 697189251Ssam wpabuf_put_u8(resp, peap_version); /* Flags */ 698189251Ssam return resp; 699189251Ssam} 700189251Ssam 701189251Ssam 702189251Ssam/** 703189251Ssam * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption 704189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 705189251Ssam * @data: Data for TLS processing 706189251Ssam * Returns: 0 on success, -1 on failure 707189251Ssam */ 708189251Ssamint eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data) 709189251Ssam{ 710189251Ssam eap_peer_tls_reset_input(data); 711189251Ssam eap_peer_tls_reset_output(data); 712252726Srpaulo return tls_connection_shutdown(data->ssl_ctx, data->conn); 713189251Ssam} 714189251Ssam 715189251Ssam 716189251Ssam/** 717189251Ssam * eap_peer_tls_status - Get TLS status 718189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 719189251Ssam * @data: Data for TLS processing 720189251Ssam * @buf: Buffer for status information 721189251Ssam * @buflen: Maximum buffer length 722189251Ssam * @verbose: Whether to include verbose status information 723189251Ssam * Returns: Number of bytes written to buf. 724189251Ssam */ 725189251Ssamint eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, 726189251Ssam char *buf, size_t buflen, int verbose) 727189251Ssam{ 728189251Ssam char name[128]; 729189251Ssam int len = 0, ret; 730189251Ssam 731252726Srpaulo if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0) 732252726Srpaulo { 733189251Ssam ret = os_snprintf(buf + len, buflen - len, 734189251Ssam "EAP TLS cipher=%s\n", name); 735189251Ssam if (ret < 0 || (size_t) ret >= buflen - len) 736189251Ssam return len; 737189251Ssam len += ret; 738189251Ssam } 739189251Ssam 740189251Ssam return len; 741189251Ssam} 742189251Ssam 743189251Ssam 744189251Ssam/** 745189251Ssam * eap_peer_tls_process_init - Initial validation/processing of EAP requests 746189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 747189251Ssam * @data: Data for TLS processing 748189251Ssam * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 749189251Ssam * @ret: Return values from EAP request validation and processing 750189251Ssam * @reqData: EAP request to be processed (eapReqData) 751189251Ssam * @len: Buffer for returning length of the remaining payload 752189251Ssam * @flags: Buffer for returning TLS flags 753189251Ssam * Returns: Pointer to payload after TLS flags and length or %NULL on failure 754189251Ssam * 755189251Ssam * This function validates the EAP header and processes the optional TLS 756189251Ssam * Message Length field. If this is the first fragment of a TLS message, the 757189251Ssam * TLS reassembly code is initialized to receive the indicated number of bytes. 758189251Ssam * 759189251Ssam * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this 760189251Ssam * function as the first step in processing received messages. They will need 761189251Ssam * to process the flags (apart from Message Length Included) that are returned 762189251Ssam * through the flags pointer and the message payload that will be returned (and 763189251Ssam * the length is returned through the len pointer). Return values (ret) are set 764189251Ssam * for continuation of EAP method processing. The caller is responsible for 765189251Ssam * setting these to indicate completion (either success or failure) based on 766189251Ssam * the authentication result. 767189251Ssam */ 768189251Ssamconst u8 * eap_peer_tls_process_init(struct eap_sm *sm, 769189251Ssam struct eap_ssl_data *data, 770189251Ssam EapType eap_type, 771189251Ssam struct eap_method_ret *ret, 772189251Ssam const struct wpabuf *reqData, 773189251Ssam size_t *len, u8 *flags) 774189251Ssam{ 775189251Ssam const u8 *pos; 776189251Ssam size_t left; 777189251Ssam unsigned int tls_msg_len; 778189251Ssam 779252726Srpaulo if (tls_get_errors(data->ssl_ctx)) { 780189251Ssam wpa_printf(MSG_INFO, "SSL: TLS errors detected"); 781189251Ssam ret->ignore = TRUE; 782189251Ssam return NULL; 783189251Ssam } 784189251Ssam 785252726Srpaulo if (eap_type == EAP_UNAUTH_TLS_TYPE) 786252726Srpaulo pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, 787252726Srpaulo EAP_VENDOR_TYPE_UNAUTH_TLS, reqData, 788252726Srpaulo &left); 789252726Srpaulo else 790252726Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, 791252726Srpaulo &left); 792189251Ssam if (pos == NULL) { 793189251Ssam ret->ignore = TRUE; 794189251Ssam return NULL; 795189251Ssam } 796189251Ssam if (left == 0) { 797189251Ssam wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags " 798189251Ssam "octet included"); 799189251Ssam if (!sm->workaround) { 800189251Ssam ret->ignore = TRUE; 801189251Ssam return NULL; 802189251Ssam } 803189251Ssam 804189251Ssam wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags " 805189251Ssam "indicates ACK frame"); 806189251Ssam *flags = 0; 807189251Ssam } else { 808189251Ssam *flags = *pos++; 809189251Ssam left--; 810189251Ssam } 811189251Ssam wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - " 812189251Ssam "Flags 0x%02x", (unsigned long) wpabuf_len(reqData), 813189251Ssam *flags); 814189251Ssam if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { 815189251Ssam if (left < 4) { 816189251Ssam wpa_printf(MSG_INFO, "SSL: Short frame with TLS " 817189251Ssam "length"); 818189251Ssam ret->ignore = TRUE; 819189251Ssam return NULL; 820189251Ssam } 821189251Ssam tls_msg_len = WPA_GET_BE32(pos); 822189251Ssam wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", 823189251Ssam tls_msg_len); 824189251Ssam if (data->tls_in_left == 0) { 825189251Ssam data->tls_in_total = tls_msg_len; 826189251Ssam data->tls_in_left = tls_msg_len; 827214734Srpaulo wpabuf_free(data->tls_in); 828189251Ssam data->tls_in = NULL; 829189251Ssam } 830189251Ssam pos += 4; 831189251Ssam left -= 4; 832252726Srpaulo 833252726Srpaulo if (left > tls_msg_len) { 834252726Srpaulo wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " 835252726Srpaulo "bytes) smaller than this fragment (%d " 836252726Srpaulo "bytes)", (int) tls_msg_len, (int) left); 837252726Srpaulo ret->ignore = TRUE; 838252726Srpaulo return NULL; 839252726Srpaulo } 840189251Ssam } 841189251Ssam 842189251Ssam ret->ignore = FALSE; 843189251Ssam ret->methodState = METHOD_MAY_CONT; 844189251Ssam ret->decision = DECISION_FAIL; 845189251Ssam ret->allowNotifications = TRUE; 846189251Ssam 847189251Ssam *len = left; 848189251Ssam return pos; 849189251Ssam} 850189251Ssam 851189251Ssam 852189251Ssam/** 853189251Ssam * eap_peer_tls_reset_input - Reset input buffers 854189251Ssam * @data: Data for TLS processing 855189251Ssam * 856189251Ssam * This function frees any allocated memory for input buffers and resets input 857189251Ssam * state. 858189251Ssam */ 859189251Ssamvoid eap_peer_tls_reset_input(struct eap_ssl_data *data) 860189251Ssam{ 861214734Srpaulo data->tls_in_left = data->tls_in_total = 0; 862214734Srpaulo wpabuf_free(data->tls_in); 863189251Ssam data->tls_in = NULL; 864189251Ssam} 865189251Ssam 866189251Ssam 867189251Ssam/** 868189251Ssam * eap_peer_tls_reset_output - Reset output buffers 869189251Ssam * @data: Data for TLS processing 870189251Ssam * 871189251Ssam * This function frees any allocated memory for output buffers and resets 872189251Ssam * output state. 873189251Ssam */ 874189251Ssamvoid eap_peer_tls_reset_output(struct eap_ssl_data *data) 875189251Ssam{ 876189251Ssam data->tls_out_pos = 0; 877214734Srpaulo wpabuf_free(data->tls_out); 878189251Ssam data->tls_out = NULL; 879189251Ssam} 880189251Ssam 881189251Ssam 882189251Ssam/** 883189251Ssam * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message 884189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 885189251Ssam * @data: Data for TLS processing 886189251Ssam * @in_data: Message received from the server 887189251Ssam * @in_decrypted: Buffer for returning a pointer to the decrypted message 888189251Ssam * Returns: 0 on success, 1 if more input data is needed, or -1 on failure 889189251Ssam */ 890189251Ssamint eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, 891189251Ssam const struct wpabuf *in_data, 892189251Ssam struct wpabuf **in_decrypted) 893189251Ssam{ 894214734Srpaulo const struct wpabuf *msg; 895189251Ssam int need_more_input; 896189251Ssam 897214734Srpaulo msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); 898189251Ssam if (msg == NULL) 899189251Ssam return need_more_input ? 1 : -1; 900189251Ssam 901252726Srpaulo *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg); 902214734Srpaulo eap_peer_tls_reset_input(data); 903189251Ssam if (*in_decrypted == NULL) { 904189251Ssam wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data"); 905189251Ssam return -1; 906189251Ssam } 907189251Ssam return 0; 908189251Ssam} 909189251Ssam 910189251Ssam 911189251Ssam/** 912189251Ssam * eap_peer_tls_encrypt - Encrypt phase 2 TLS message 913189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 914189251Ssam * @data: Data for TLS processing 915189251Ssam * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 916189251Ssam * @peap_version: Version number for EAP-PEAP/TTLS 917189251Ssam * @id: EAP identifier for the response 918189251Ssam * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments 919189251Ssam * @out_data: Buffer for returning a pointer to the encrypted response message 920189251Ssam * Returns: 0 on success, -1 on failure 921189251Ssam */ 922189251Ssamint eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, 923189251Ssam EapType eap_type, int peap_version, u8 id, 924189251Ssam const struct wpabuf *in_data, 925189251Ssam struct wpabuf **out_data) 926189251Ssam{ 927189251Ssam if (in_data) { 928189251Ssam eap_peer_tls_reset_output(data); 929252726Srpaulo data->tls_out = tls_connection_encrypt(data->ssl_ctx, 930252726Srpaulo data->conn, in_data); 931214734Srpaulo if (data->tls_out == NULL) { 932189251Ssam wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 " 933189251Ssam "data (in_len=%lu)", 934189251Ssam (unsigned long) wpabuf_len(in_data)); 935189251Ssam eap_peer_tls_reset_output(data); 936189251Ssam return -1; 937189251Ssam } 938189251Ssam } 939189251Ssam 940189251Ssam return eap_tls_process_output(data, eap_type, peap_version, id, 0, 941189251Ssam out_data); 942189251Ssam} 943189251Ssam 944189251Ssam 945189251Ssam/** 946189251Ssam * eap_peer_select_phase2_methods - Select phase 2 EAP method 947189251Ssam * @config: Pointer to the network configuration 948189251Ssam * @prefix: 'phase2' configuration prefix, e.g., "auth=" 949189251Ssam * @types: Buffer for returning allocated list of allowed EAP methods 950189251Ssam * @num_types: Buffer for returning number of allocated EAP methods 951189251Ssam * Returns: 0 on success, -1 on failure 952189251Ssam * 953189251Ssam * This function is used to parse EAP method list and select allowed methods 954189251Ssam * for Phase2 authentication. 955189251Ssam */ 956189251Ssamint eap_peer_select_phase2_methods(struct eap_peer_config *config, 957189251Ssam const char *prefix, 958189251Ssam struct eap_method_type **types, 959189251Ssam size_t *num_types) 960189251Ssam{ 961189251Ssam char *start, *pos, *buf; 962189251Ssam struct eap_method_type *methods = NULL, *_methods; 963189251Ssam u8 method; 964189251Ssam size_t num_methods = 0, prefix_len; 965189251Ssam 966189251Ssam if (config == NULL || config->phase2 == NULL) 967189251Ssam goto get_defaults; 968189251Ssam 969189251Ssam start = buf = os_strdup(config->phase2); 970189251Ssam if (buf == NULL) 971189251Ssam return -1; 972189251Ssam 973189251Ssam prefix_len = os_strlen(prefix); 974189251Ssam 975189251Ssam while (start && *start != '\0') { 976189251Ssam int vendor; 977189251Ssam pos = os_strstr(start, prefix); 978189251Ssam if (pos == NULL) 979189251Ssam break; 980189251Ssam if (start != pos && *(pos - 1) != ' ') { 981189251Ssam start = pos + prefix_len; 982189251Ssam continue; 983189251Ssam } 984189251Ssam 985189251Ssam start = pos + prefix_len; 986189251Ssam pos = os_strchr(start, ' '); 987189251Ssam if (pos) 988189251Ssam *pos++ = '\0'; 989189251Ssam method = eap_get_phase2_type(start, &vendor); 990189251Ssam if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { 991189251Ssam wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " 992189251Ssam "method '%s'", start); 993189251Ssam } else { 994189251Ssam num_methods++; 995252726Srpaulo _methods = os_realloc_array(methods, num_methods, 996252726Srpaulo sizeof(*methods)); 997189251Ssam if (_methods == NULL) { 998189251Ssam os_free(methods); 999189251Ssam os_free(buf); 1000189251Ssam return -1; 1001189251Ssam } 1002189251Ssam methods = _methods; 1003189251Ssam methods[num_methods - 1].vendor = vendor; 1004189251Ssam methods[num_methods - 1].method = method; 1005189251Ssam } 1006189251Ssam 1007189251Ssam start = pos; 1008189251Ssam } 1009189251Ssam 1010189251Ssam os_free(buf); 1011189251Ssam 1012189251Ssamget_defaults: 1013189251Ssam if (methods == NULL) 1014189251Ssam methods = eap_get_phase2_types(config, &num_methods); 1015189251Ssam 1016189251Ssam if (methods == NULL) { 1017189251Ssam wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available"); 1018189251Ssam return -1; 1019189251Ssam } 1020189251Ssam wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types", 1021189251Ssam (u8 *) methods, 1022189251Ssam num_methods * sizeof(struct eap_method_type)); 1023189251Ssam 1024189251Ssam *types = methods; 1025189251Ssam *num_types = num_methods; 1026189251Ssam 1027189251Ssam return 0; 1028189251Ssam} 1029189251Ssam 1030189251Ssam 1031189251Ssam/** 1032189251Ssam * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2 1033189251Ssam * @types: Buffer for returning allocated list of allowed EAP methods 1034189251Ssam * @num_types: Buffer for returning number of allocated EAP methods 1035189251Ssam * @hdr: EAP-Request header (and the following EAP type octet) 1036189251Ssam * @resp: Buffer for returning the EAP-Nak message 1037189251Ssam * Returns: 0 on success, -1 on failure 1038189251Ssam */ 1039189251Ssamint eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, 1040189251Ssam struct eap_hdr *hdr, struct wpabuf **resp) 1041189251Ssam{ 1042189251Ssam u8 *pos = (u8 *) (hdr + 1); 1043189251Ssam size_t i; 1044189251Ssam 1045189251Ssam /* TODO: add support for expanded Nak */ 1046189251Ssam wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos); 1047189251Ssam wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types", 1048189251Ssam (u8 *) types, num_types * sizeof(struct eap_method_type)); 1049189251Ssam *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types, 1050189251Ssam EAP_CODE_RESPONSE, hdr->identifier); 1051189251Ssam if (*resp == NULL) 1052189251Ssam return -1; 1053189251Ssam 1054189251Ssam for (i = 0; i < num_types; i++) { 1055189251Ssam if (types[i].vendor == EAP_VENDOR_IETF && 1056189251Ssam types[i].method < 256) 1057189251Ssam wpabuf_put_u8(*resp, types[i].method); 1058189251Ssam } 1059189251Ssam 1060189251Ssam eap_update_len(*resp); 1061189251Ssam 1062189251Ssam return 0; 1063189251Ssam} 1064