1189251Ssam/* 2189251Ssam * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions 3214734Srpaulo * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#include "common.h" 18214734Srpaulo#include "crypto/sha1.h" 19214734Srpaulo#include "crypto/tls.h" 20189251Ssam#include "eap_i.h" 21189251Ssam#include "eap_tls_common.h" 22189251Ssam#include "eap_config.h" 23189251Ssam 24189251Ssam 25189251Ssamstatic int eap_tls_check_blob(struct eap_sm *sm, const char **name, 26189251Ssam const u8 **data, size_t *data_len) 27189251Ssam{ 28189251Ssam const struct wpa_config_blob *blob; 29189251Ssam 30189251Ssam if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0) 31189251Ssam return 0; 32189251Ssam 33189251Ssam blob = eap_get_config_blob(sm, *name + 7); 34189251Ssam if (blob == NULL) { 35189251Ssam wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not " 36189251Ssam "found", __func__, *name + 7); 37189251Ssam return -1; 38189251Ssam } 39189251Ssam 40189251Ssam *name = NULL; 41189251Ssam *data = blob->data; 42189251Ssam *data_len = blob->len; 43189251Ssam 44189251Ssam return 0; 45189251Ssam} 46189251Ssam 47189251Ssam 48209158Srpaulostatic void eap_tls_params_flags(struct tls_connection_params *params, 49209158Srpaulo const char *txt) 50209158Srpaulo{ 51209158Srpaulo if (txt == NULL) 52209158Srpaulo return; 53209158Srpaulo if (os_strstr(txt, "tls_allow_md5=1")) 54209158Srpaulo params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5; 55209158Srpaulo if (os_strstr(txt, "tls_disable_time_checks=1")) 56209158Srpaulo params->flags |= TLS_CONN_DISABLE_TIME_CHECKS; 57209158Srpaulo} 58209158Srpaulo 59209158Srpaulo 60189251Ssamstatic void eap_tls_params_from_conf1(struct tls_connection_params *params, 61189251Ssam struct eap_peer_config *config) 62189251Ssam{ 63189251Ssam params->ca_cert = (char *) config->ca_cert; 64189251Ssam params->ca_path = (char *) config->ca_path; 65189251Ssam params->client_cert = (char *) config->client_cert; 66189251Ssam params->private_key = (char *) config->private_key; 67189251Ssam params->private_key_passwd = (char *) config->private_key_passwd; 68189251Ssam params->dh_file = (char *) config->dh_file; 69189251Ssam params->subject_match = (char *) config->subject_match; 70189251Ssam params->altsubject_match = (char *) config->altsubject_match; 71189251Ssam params->engine = config->engine; 72189251Ssam params->engine_id = config->engine_id; 73189251Ssam params->pin = config->pin; 74189251Ssam params->key_id = config->key_id; 75189251Ssam params->cert_id = config->cert_id; 76189251Ssam params->ca_cert_id = config->ca_cert_id; 77209158Srpaulo eap_tls_params_flags(params, config->phase1); 78189251Ssam} 79189251Ssam 80189251Ssam 81189251Ssamstatic void eap_tls_params_from_conf2(struct tls_connection_params *params, 82189251Ssam struct eap_peer_config *config) 83189251Ssam{ 84189251Ssam params->ca_cert = (char *) config->ca_cert2; 85189251Ssam params->ca_path = (char *) config->ca_path2; 86189251Ssam params->client_cert = (char *) config->client_cert2; 87189251Ssam params->private_key = (char *) config->private_key2; 88189251Ssam params->private_key_passwd = (char *) config->private_key2_passwd; 89189251Ssam params->dh_file = (char *) config->dh_file2; 90189251Ssam params->subject_match = (char *) config->subject_match2; 91189251Ssam params->altsubject_match = (char *) config->altsubject_match2; 92189251Ssam params->engine = config->engine2; 93189251Ssam params->engine_id = config->engine2_id; 94189251Ssam params->pin = config->pin2; 95189251Ssam params->key_id = config->key2_id; 96189251Ssam params->cert_id = config->cert2_id; 97189251Ssam params->ca_cert_id = config->ca_cert2_id; 98209158Srpaulo eap_tls_params_flags(params, config->phase2); 99189251Ssam} 100189251Ssam 101189251Ssam 102189251Ssamstatic int eap_tls_params_from_conf(struct eap_sm *sm, 103189251Ssam struct eap_ssl_data *data, 104189251Ssam struct tls_connection_params *params, 105189251Ssam struct eap_peer_config *config, int phase2) 106189251Ssam{ 107189251Ssam os_memset(params, 0, sizeof(*params)); 108189251Ssam if (phase2) { 109189251Ssam wpa_printf(MSG_DEBUG, "TLS: using phase2 config options"); 110189251Ssam eap_tls_params_from_conf2(params, config); 111189251Ssam } else { 112189251Ssam wpa_printf(MSG_DEBUG, "TLS: using phase1 config options"); 113189251Ssam eap_tls_params_from_conf1(params, config); 114189251Ssam } 115189251Ssam params->tls_ia = data->tls_ia; 116189251Ssam 117189251Ssam /* 118189251Ssam * Use blob data, if available. Otherwise, leave reference to external 119189251Ssam * file as-is. 120189251Ssam */ 121189251Ssam if (eap_tls_check_blob(sm, ¶ms->ca_cert, ¶ms->ca_cert_blob, 122189251Ssam ¶ms->ca_cert_blob_len) || 123189251Ssam eap_tls_check_blob(sm, ¶ms->client_cert, 124189251Ssam ¶ms->client_cert_blob, 125189251Ssam ¶ms->client_cert_blob_len) || 126189251Ssam eap_tls_check_blob(sm, ¶ms->private_key, 127189251Ssam ¶ms->private_key_blob, 128189251Ssam ¶ms->private_key_blob_len) || 129189251Ssam eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, 130189251Ssam ¶ms->dh_blob_len)) { 131189251Ssam wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); 132189251Ssam return -1; 133189251Ssam } 134189251Ssam 135189251Ssam return 0; 136189251Ssam} 137189251Ssam 138189251Ssam 139189251Ssamstatic int eap_tls_init_connection(struct eap_sm *sm, 140189251Ssam struct eap_ssl_data *data, 141189251Ssam struct eap_peer_config *config, 142189251Ssam struct tls_connection_params *params) 143189251Ssam{ 144189251Ssam int res; 145189251Ssam 146189251Ssam data->conn = tls_connection_init(sm->ssl_ctx); 147189251Ssam if (data->conn == NULL) { 148189251Ssam wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " 149189251Ssam "connection"); 150189251Ssam return -1; 151189251Ssam } 152189251Ssam 153189251Ssam res = tls_connection_set_params(sm->ssl_ctx, data->conn, params); 154189251Ssam if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) { 155189251Ssam /* 156189251Ssam * At this point with the pkcs11 engine the PIN might be wrong. 157189251Ssam * We reset the PIN in the configuration to be sure to not use 158189251Ssam * it again and the calling function must request a new one. 159189251Ssam */ 160189251Ssam os_free(config->pin); 161189251Ssam config->pin = NULL; 162189251Ssam } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) { 163189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to load private key"); 164189251Ssam /* 165189251Ssam * We do not know exactly but maybe the PIN was wrong, 166189251Ssam * so ask for a new one. 167189251Ssam */ 168189251Ssam os_free(config->pin); 169189251Ssam config->pin = NULL; 170189251Ssam eap_sm_request_pin(sm); 171189251Ssam sm->ignore = TRUE; 172214734Srpaulo tls_connection_deinit(sm->ssl_ctx, data->conn); 173214734Srpaulo data->conn = NULL; 174189251Ssam return -1; 175189251Ssam } else if (res) { 176189251Ssam wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection " 177189251Ssam "parameters"); 178214734Srpaulo tls_connection_deinit(sm->ssl_ctx, data->conn); 179214734Srpaulo data->conn = NULL; 180189251Ssam return -1; 181189251Ssam } 182189251Ssam 183189251Ssam return 0; 184189251Ssam} 185189251Ssam 186189251Ssam 187189251Ssam/** 188189251Ssam * eap_peer_tls_ssl_init - Initialize shared TLS functionality 189189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 190189251Ssam * @data: Data for TLS processing 191189251Ssam * @config: Pointer to the network configuration 192189251Ssam * Returns: 0 on success, -1 on failure 193189251Ssam * 194189251Ssam * This function is used to initialize shared TLS functionality for EAP-TLS, 195189251Ssam * EAP-PEAP, EAP-TTLS, and EAP-FAST. 196189251Ssam */ 197189251Ssamint eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, 198189251Ssam struct eap_peer_config *config) 199189251Ssam{ 200189251Ssam struct tls_connection_params params; 201189251Ssam 202189251Ssam if (config == NULL) 203189251Ssam return -1; 204189251Ssam 205189251Ssam data->eap = sm; 206189251Ssam data->phase2 = sm->init_phase2; 207189251Ssam if (eap_tls_params_from_conf(sm, data, ¶ms, config, data->phase2) < 208189251Ssam 0) 209189251Ssam return -1; 210189251Ssam 211189251Ssam if (eap_tls_init_connection(sm, data, config, ¶ms) < 0) 212189251Ssam return -1; 213189251Ssam 214189251Ssam data->tls_out_limit = config->fragment_size; 215189251Ssam if (data->phase2) { 216189251Ssam /* Limit the fragment size in the inner TLS authentication 217189251Ssam * since the outer authentication with EAP-PEAP does not yet 218189251Ssam * support fragmentation */ 219189251Ssam if (data->tls_out_limit > 100) 220189251Ssam data->tls_out_limit -= 100; 221189251Ssam } 222189251Ssam 223189251Ssam if (config->phase1 && 224189251Ssam os_strstr(config->phase1, "include_tls_length=1")) { 225189251Ssam wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in " 226189251Ssam "unfragmented packets"); 227189251Ssam data->include_tls_length = 1; 228189251Ssam } 229189251Ssam 230189251Ssam return 0; 231189251Ssam} 232189251Ssam 233189251Ssam 234189251Ssam/** 235189251Ssam * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality 236189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 237189251Ssam * @data: Data for TLS processing 238189251Ssam * 239189251Ssam * This function deinitializes shared TLS functionality that was initialized 240189251Ssam * with eap_peer_tls_ssl_init(). 241189251Ssam */ 242189251Ssamvoid eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) 243189251Ssam{ 244189251Ssam tls_connection_deinit(sm->ssl_ctx, data->conn); 245189251Ssam eap_peer_tls_reset_input(data); 246189251Ssam eap_peer_tls_reset_output(data); 247189251Ssam} 248189251Ssam 249189251Ssam 250189251Ssam/** 251189251Ssam * eap_peer_tls_derive_key - Derive a key based on TLS session data 252189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 253189251Ssam * @data: Data for TLS processing 254189251Ssam * @label: Label string for deriving the keys, e.g., "client EAP encryption" 255189251Ssam * @len: Length of the key material to generate (usually 64 for MSK) 256189251Ssam * Returns: Pointer to allocated key on success or %NULL on failure 257189251Ssam * 258189251Ssam * This function uses TLS-PRF to generate pseudo-random data based on the TLS 259189251Ssam * session data (client/server random and master key). Each key type may use a 260189251Ssam * different label to bind the key usage into the generated material. 261189251Ssam * 262189251Ssam * The caller is responsible for freeing the returned buffer. 263189251Ssam */ 264189251Ssamu8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, 265189251Ssam const char *label, size_t len) 266189251Ssam{ 267189251Ssam struct tls_keys keys; 268189251Ssam u8 *rnd = NULL, *out; 269189251Ssam 270189251Ssam out = os_malloc(len); 271189251Ssam if (out == NULL) 272189251Ssam return NULL; 273189251Ssam 274189251Ssam /* First, try to use TLS library function for PRF, if available. */ 275189251Ssam if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) == 276189251Ssam 0) 277189251Ssam return out; 278189251Ssam 279189251Ssam /* 280189251Ssam * TLS library did not support key generation, so get the needed TLS 281189251Ssam * session parameters and use an internal implementation of TLS PRF to 282189251Ssam * derive the key. 283189251Ssam */ 284189251Ssam if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) 285189251Ssam goto fail; 286189251Ssam 287189251Ssam if (keys.client_random == NULL || keys.server_random == NULL || 288189251Ssam keys.master_key == NULL) 289189251Ssam goto fail; 290189251Ssam 291189251Ssam rnd = os_malloc(keys.client_random_len + keys.server_random_len); 292189251Ssam if (rnd == NULL) 293189251Ssam goto fail; 294189251Ssam os_memcpy(rnd, keys.client_random, keys.client_random_len); 295189251Ssam os_memcpy(rnd + keys.client_random_len, keys.server_random, 296189251Ssam keys.server_random_len); 297189251Ssam 298189251Ssam if (tls_prf(keys.master_key, keys.master_key_len, 299189251Ssam label, rnd, keys.client_random_len + 300189251Ssam keys.server_random_len, out, len)) 301189251Ssam goto fail; 302189251Ssam 303189251Ssam os_free(rnd); 304189251Ssam return out; 305189251Ssam 306189251Ssamfail: 307189251Ssam os_free(out); 308189251Ssam os_free(rnd); 309189251Ssam return NULL; 310189251Ssam} 311189251Ssam 312189251Ssam 313189251Ssam/** 314189251Ssam * eap_peer_tls_reassemble_fragment - Reassemble a received fragment 315189251Ssam * @data: Data for TLS processing 316189251Ssam * @in_data: Next incoming TLS segment 317189251Ssam * Returns: 0 on success, 1 if more data is needed for the full message, or 318189251Ssam * -1 on error 319189251Ssam */ 320189251Ssamstatic int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, 321214734Srpaulo const struct wpabuf *in_data) 322189251Ssam{ 323214734Srpaulo size_t tls_in_len, in_len; 324189251Ssam 325214734Srpaulo tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0; 326214734Srpaulo in_len = in_data ? wpabuf_len(in_data) : 0; 327214734Srpaulo 328214734Srpaulo if (tls_in_len + in_len == 0) { 329189251Ssam /* No message data received?! */ 330189251Ssam wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: " 331189251Ssam "tls_in_left=%lu tls_in_len=%lu in_len=%lu", 332189251Ssam (unsigned long) data->tls_in_left, 333214734Srpaulo (unsigned long) tls_in_len, 334189251Ssam (unsigned long) in_len); 335189251Ssam eap_peer_tls_reset_input(data); 336189251Ssam return -1; 337189251Ssam } 338189251Ssam 339214734Srpaulo if (tls_in_len + in_len > 65536) { 340189251Ssam /* 341189251Ssam * Limit length to avoid rogue servers from causing large 342189251Ssam * memory allocations. 343189251Ssam */ 344189251Ssam wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over " 345189251Ssam "64 kB)"); 346189251Ssam eap_peer_tls_reset_input(data); 347189251Ssam return -1; 348189251Ssam } 349189251Ssam 350189251Ssam if (in_len > data->tls_in_left) { 351189251Ssam /* Sender is doing something odd - reject message */ 352189251Ssam wpa_printf(MSG_INFO, "SSL: more data than TLS message length " 353189251Ssam "indicated"); 354189251Ssam eap_peer_tls_reset_input(data); 355189251Ssam return -1; 356189251Ssam } 357189251Ssam 358214734Srpaulo if (wpabuf_resize(&data->tls_in, in_len) < 0) { 359189251Ssam wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS " 360189251Ssam "data"); 361189251Ssam eap_peer_tls_reset_input(data); 362189251Ssam return -1; 363189251Ssam } 364214734Srpaulo wpabuf_put_buf(data->tls_in, in_data); 365189251Ssam data->tls_in_left -= in_len; 366189251Ssam 367189251Ssam if (data->tls_in_left > 0) { 368189251Ssam wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input " 369189251Ssam "data", (unsigned long) data->tls_in_left); 370189251Ssam return 1; 371189251Ssam } 372189251Ssam 373189251Ssam return 0; 374189251Ssam} 375189251Ssam 376189251Ssam 377189251Ssam/** 378189251Ssam * eap_peer_tls_data_reassemble - Reassemble TLS data 379189251Ssam * @data: Data for TLS processing 380189251Ssam * @in_data: Next incoming TLS segment 381189251Ssam * @need_more_input: Variable for returning whether more input data is needed 382189251Ssam * to reassemble this TLS packet 383189251Ssam * Returns: Pointer to output data, %NULL on error or when more data is needed 384189251Ssam * for the full message (in which case, *need_more_input is also set to 1). 385189251Ssam * 386189251Ssam * This function reassembles TLS fragments. Caller must not free the returned 387189251Ssam * data buffer since an internal pointer to it is maintained. 388189251Ssam */ 389214734Srpaulostatic const struct wpabuf * eap_peer_tls_data_reassemble( 390214734Srpaulo struct eap_ssl_data *data, const struct wpabuf *in_data, 391214734Srpaulo int *need_more_input) 392189251Ssam{ 393189251Ssam *need_more_input = 0; 394189251Ssam 395214734Srpaulo if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) { 396189251Ssam /* Message has fragments */ 397214734Srpaulo int res = eap_peer_tls_reassemble_fragment(data, in_data); 398189251Ssam if (res) { 399189251Ssam if (res == 1) 400189251Ssam *need_more_input = 1; 401189251Ssam return NULL; 402189251Ssam } 403189251Ssam 404189251Ssam /* Message is now fully reassembled. */ 405189251Ssam } else { 406189251Ssam /* No fragments in this message, so just make a copy of it. */ 407189251Ssam data->tls_in_left = 0; 408214734Srpaulo data->tls_in = wpabuf_dup(in_data); 409189251Ssam if (data->tls_in == NULL) 410189251Ssam return NULL; 411189251Ssam } 412189251Ssam 413189251Ssam return data->tls_in; 414189251Ssam} 415189251Ssam 416189251Ssam 417189251Ssam/** 418189251Ssam * eap_tls_process_input - Process incoming TLS message 419189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 420189251Ssam * @data: Data for TLS processing 421189251Ssam * @in_data: Message received from the server 422189251Ssam * @in_len: Length of in_data 423189251Ssam * @out_data: Buffer for returning a pointer to application data (if available) 424189251Ssam * Returns: 0 on success, 1 if more input data is needed, 2 if application data 425189251Ssam * is available, -1 on failure 426189251Ssam */ 427189251Ssamstatic int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, 428189251Ssam const u8 *in_data, size_t in_len, 429189251Ssam struct wpabuf **out_data) 430189251Ssam{ 431214734Srpaulo const struct wpabuf *msg; 432189251Ssam int need_more_input; 433214734Srpaulo struct wpabuf *appl_data; 434214734Srpaulo struct wpabuf buf; 435189251Ssam 436214734Srpaulo wpabuf_set(&buf, in_data, in_len); 437214734Srpaulo msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input); 438189251Ssam if (msg == NULL) 439189251Ssam return need_more_input ? 1 : -1; 440189251Ssam 441189251Ssam /* Full TLS message reassembled - continue handshake processing */ 442189251Ssam if (data->tls_out) { 443189251Ssam /* This should not happen.. */ 444189251Ssam wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending " 445189251Ssam "tls_out data even though tls_out_len = 0"); 446214734Srpaulo wpabuf_free(data->tls_out); 447189251Ssam WPA_ASSERT(data->tls_out == NULL); 448189251Ssam } 449189251Ssam appl_data = NULL; 450189251Ssam data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn, 451214734Srpaulo msg, &appl_data); 452189251Ssam 453189251Ssam eap_peer_tls_reset_input(data); 454189251Ssam 455189251Ssam if (appl_data && 456189251Ssam tls_connection_established(sm->ssl_ctx, data->conn) && 457189251Ssam !tls_connection_get_failed(sm->ssl_ctx, data->conn)) { 458214734Srpaulo wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data", 459214734Srpaulo appl_data); 460214734Srpaulo *out_data = appl_data; 461189251Ssam return 2; 462189251Ssam } 463189251Ssam 464214734Srpaulo wpabuf_free(appl_data); 465189251Ssam 466189251Ssam return 0; 467189251Ssam} 468189251Ssam 469189251Ssam 470189251Ssam/** 471189251Ssam * eap_tls_process_output - Process outgoing TLS message 472189251Ssam * @data: Data for TLS processing 473189251Ssam * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 474189251Ssam * @peap_version: Version number for EAP-PEAP/TTLS 475189251Ssam * @id: EAP identifier for the response 476189251Ssam * @ret: Return value to use on success 477189251Ssam * @out_data: Buffer for returning the allocated output buffer 478189251Ssam * Returns: ret (0 or 1) on success, -1 on failure 479189251Ssam */ 480189251Ssamstatic int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, 481189251Ssam int peap_version, u8 id, int ret, 482189251Ssam struct wpabuf **out_data) 483189251Ssam{ 484189251Ssam size_t len; 485189251Ssam u8 *flags; 486189251Ssam int more_fragments, length_included; 487214734Srpaulo 488214734Srpaulo if (data->tls_out == NULL) 489214734Srpaulo return -1; 490214734Srpaulo len = wpabuf_len(data->tls_out) - data->tls_out_pos; 491189251Ssam wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " 492189251Ssam "%lu bytes)", 493214734Srpaulo (unsigned long) len, 494214734Srpaulo (unsigned long) wpabuf_len(data->tls_out)); 495189251Ssam 496189251Ssam /* 497189251Ssam * Limit outgoing message to the configured maximum size. Fragment 498189251Ssam * message if needed. 499189251Ssam */ 500189251Ssam if (len > data->tls_out_limit) { 501189251Ssam more_fragments = 1; 502189251Ssam len = data->tls_out_limit; 503189251Ssam wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments " 504189251Ssam "will follow", (unsigned long) len); 505189251Ssam } else 506189251Ssam more_fragments = 0; 507189251Ssam 508189251Ssam length_included = data->tls_out_pos == 0 && 509214734Srpaulo (wpabuf_len(data->tls_out) > data->tls_out_limit || 510189251Ssam data->include_tls_length); 511189251Ssam if (!length_included && 512189251Ssam eap_type == EAP_TYPE_PEAP && peap_version == 0 && 513189251Ssam !tls_connection_established(data->eap->ssl_ctx, data->conn)) { 514189251Ssam /* 515189251Ssam * Windows Server 2008 NPS really wants to have the TLS Message 516189251Ssam * length included in phase 0 even for unfragmented frames or 517189251Ssam * it will get very confused with Compound MAC calculation and 518189251Ssam * Outer TLVs. 519189251Ssam */ 520189251Ssam length_included = 1; 521189251Ssam } 522189251Ssam 523189251Ssam *out_data = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 524189251Ssam 1 + length_included * 4 + len, 525189251Ssam EAP_CODE_RESPONSE, id); 526189251Ssam if (*out_data == NULL) 527189251Ssam return -1; 528189251Ssam 529189251Ssam flags = wpabuf_put(*out_data, 1); 530189251Ssam *flags = peap_version; 531189251Ssam if (more_fragments) 532189251Ssam *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; 533189251Ssam if (length_included) { 534189251Ssam *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; 535214734Srpaulo wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out)); 536189251Ssam } 537189251Ssam 538214734Srpaulo wpabuf_put_data(*out_data, 539214734Srpaulo wpabuf_head_u8(data->tls_out) + data->tls_out_pos, 540214734Srpaulo len); 541189251Ssam data->tls_out_pos += len; 542189251Ssam 543189251Ssam if (!more_fragments) 544189251Ssam eap_peer_tls_reset_output(data); 545189251Ssam 546189251Ssam return ret; 547189251Ssam} 548189251Ssam 549189251Ssam 550189251Ssam/** 551189251Ssam * eap_peer_tls_process_helper - Process TLS handshake message 552189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 553189251Ssam * @data: Data for TLS processing 554189251Ssam * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 555189251Ssam * @peap_version: Version number for EAP-PEAP/TTLS 556189251Ssam * @id: EAP identifier for the response 557189251Ssam * @in_data: Message received from the server 558189251Ssam * @in_len: Length of in_data 559189251Ssam * @out_data: Buffer for returning a pointer to the response message 560189251Ssam * Returns: 0 on success, 1 if more input data is needed, 2 if application data 561189251Ssam * is available, or -1 on failure 562189251Ssam * 563189251Ssam * This function can be used to process TLS handshake messages. It reassembles 564189251Ssam * the received fragments and uses a TLS library to process the messages. The 565189251Ssam * response data from the TLS library is fragmented to suitable output messages 566189251Ssam * that the caller can send out. 567189251Ssam * 568189251Ssam * out_data is used to return the response message if the return value of this 569189251Ssam * function is 0, 2, or -1. In case of failure, the message is likely a TLS 570189251Ssam * alarm message. The caller is responsible for freeing the allocated buffer if 571189251Ssam * *out_data is not %NULL. 572189251Ssam * 573189251Ssam * This function is called for each received TLS message during the TLS 574189251Ssam * handshake after eap_peer_tls_process_init() call and possible processing of 575189251Ssam * TLS Flags field. Once the handshake has been completed, i.e., when 576189251Ssam * tls_connection_established() returns 1, EAP method specific decrypting of 577189251Ssam * the tunneled data is used. 578189251Ssam */ 579189251Ssamint eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, 580189251Ssam EapType eap_type, int peap_version, 581189251Ssam u8 id, const u8 *in_data, size_t in_len, 582189251Ssam struct wpabuf **out_data) 583189251Ssam{ 584189251Ssam int ret = 0; 585189251Ssam 586189251Ssam *out_data = NULL; 587189251Ssam 588214734Srpaulo if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 0) { 589189251Ssam wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output " 590189251Ssam "fragments are waiting to be sent out"); 591189251Ssam return -1; 592189251Ssam } 593189251Ssam 594214734Srpaulo if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { 595189251Ssam /* 596189251Ssam * No more data to send out - expect to receive more data from 597189251Ssam * the AS. 598189251Ssam */ 599189251Ssam int res = eap_tls_process_input(sm, data, in_data, in_len, 600189251Ssam out_data); 601189251Ssam if (res) { 602189251Ssam /* 603189251Ssam * Input processing failed (res = -1) or more data is 604189251Ssam * needed (res = 1). 605189251Ssam */ 606189251Ssam return res; 607189251Ssam } 608189251Ssam 609189251Ssam /* 610189251Ssam * The incoming message has been reassembled and processed. The 611189251Ssam * response was allocated into data->tls_out buffer. 612189251Ssam */ 613189251Ssam } 614189251Ssam 615189251Ssam if (data->tls_out == NULL) { 616189251Ssam /* 617189251Ssam * No outgoing fragments remaining from the previous message 618189251Ssam * and no new message generated. This indicates an error in TLS 619189251Ssam * processing. 620189251Ssam */ 621189251Ssam eap_peer_tls_reset_output(data); 622189251Ssam return -1; 623189251Ssam } 624189251Ssam 625189251Ssam if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { 626189251Ssam /* TLS processing has failed - return error */ 627189251Ssam wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " 628189251Ssam "report error"); 629189251Ssam ret = -1; 630189251Ssam /* TODO: clean pin if engine used? */ 631189251Ssam } 632189251Ssam 633214734Srpaulo if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { 634189251Ssam /* 635189251Ssam * TLS negotiation should now be complete since all other cases 636189251Ssam * needing more data should have been caught above based on 637189251Ssam * the TLS Message Length field. 638189251Ssam */ 639189251Ssam wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); 640214734Srpaulo wpabuf_free(data->tls_out); 641189251Ssam data->tls_out = NULL; 642189251Ssam return 1; 643189251Ssam } 644189251Ssam 645189251Ssam /* Send the pending message (in fragments, if needed). */ 646189251Ssam return eap_tls_process_output(data, eap_type, peap_version, id, ret, 647189251Ssam out_data); 648189251Ssam} 649189251Ssam 650189251Ssam 651189251Ssam/** 652189251Ssam * eap_peer_tls_build_ack - Build a TLS ACK frame 653189251Ssam * @id: EAP identifier for the response 654189251Ssam * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 655189251Ssam * @peap_version: Version number for EAP-PEAP/TTLS 656189251Ssam * Returns: Pointer to the allocated ACK frame or %NULL on failure 657189251Ssam */ 658189251Ssamstruct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, 659189251Ssam int peap_version) 660189251Ssam{ 661189251Ssam struct wpabuf *resp; 662189251Ssam 663189251Ssam resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_RESPONSE, 664189251Ssam id); 665189251Ssam if (resp == NULL) 666189251Ssam return NULL; 667189251Ssam wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)", 668189251Ssam (int) eap_type, id, peap_version); 669189251Ssam wpabuf_put_u8(resp, peap_version); /* Flags */ 670189251Ssam return resp; 671189251Ssam} 672189251Ssam 673189251Ssam 674189251Ssam/** 675189251Ssam * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption 676189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 677189251Ssam * @data: Data for TLS processing 678189251Ssam * Returns: 0 on success, -1 on failure 679189251Ssam */ 680189251Ssamint eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data) 681189251Ssam{ 682189251Ssam eap_peer_tls_reset_input(data); 683189251Ssam eap_peer_tls_reset_output(data); 684189251Ssam return tls_connection_shutdown(sm->ssl_ctx, data->conn); 685189251Ssam} 686189251Ssam 687189251Ssam 688189251Ssam/** 689189251Ssam * eap_peer_tls_status - Get TLS status 690189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 691189251Ssam * @data: Data for TLS processing 692189251Ssam * @buf: Buffer for status information 693189251Ssam * @buflen: Maximum buffer length 694189251Ssam * @verbose: Whether to include verbose status information 695189251Ssam * Returns: Number of bytes written to buf. 696189251Ssam */ 697189251Ssamint eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, 698189251Ssam char *buf, size_t buflen, int verbose) 699189251Ssam{ 700189251Ssam char name[128]; 701189251Ssam int len = 0, ret; 702189251Ssam 703189251Ssam if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) { 704189251Ssam ret = os_snprintf(buf + len, buflen - len, 705189251Ssam "EAP TLS cipher=%s\n", name); 706189251Ssam if (ret < 0 || (size_t) ret >= buflen - len) 707189251Ssam return len; 708189251Ssam len += ret; 709189251Ssam } 710189251Ssam 711189251Ssam return len; 712189251Ssam} 713189251Ssam 714189251Ssam 715189251Ssam/** 716189251Ssam * eap_peer_tls_process_init - Initial validation/processing of EAP requests 717189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 718189251Ssam * @data: Data for TLS processing 719189251Ssam * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 720189251Ssam * @ret: Return values from EAP request validation and processing 721189251Ssam * @reqData: EAP request to be processed (eapReqData) 722189251Ssam * @len: Buffer for returning length of the remaining payload 723189251Ssam * @flags: Buffer for returning TLS flags 724189251Ssam * Returns: Pointer to payload after TLS flags and length or %NULL on failure 725189251Ssam * 726189251Ssam * This function validates the EAP header and processes the optional TLS 727189251Ssam * Message Length field. If this is the first fragment of a TLS message, the 728189251Ssam * TLS reassembly code is initialized to receive the indicated number of bytes. 729189251Ssam * 730189251Ssam * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this 731189251Ssam * function as the first step in processing received messages. They will need 732189251Ssam * to process the flags (apart from Message Length Included) that are returned 733189251Ssam * through the flags pointer and the message payload that will be returned (and 734189251Ssam * the length is returned through the len pointer). Return values (ret) are set 735189251Ssam * for continuation of EAP method processing. The caller is responsible for 736189251Ssam * setting these to indicate completion (either success or failure) based on 737189251Ssam * the authentication result. 738189251Ssam */ 739189251Ssamconst u8 * eap_peer_tls_process_init(struct eap_sm *sm, 740189251Ssam struct eap_ssl_data *data, 741189251Ssam EapType eap_type, 742189251Ssam struct eap_method_ret *ret, 743189251Ssam const struct wpabuf *reqData, 744189251Ssam size_t *len, u8 *flags) 745189251Ssam{ 746189251Ssam const u8 *pos; 747189251Ssam size_t left; 748189251Ssam unsigned int tls_msg_len; 749189251Ssam 750189251Ssam if (tls_get_errors(sm->ssl_ctx)) { 751189251Ssam wpa_printf(MSG_INFO, "SSL: TLS errors detected"); 752189251Ssam ret->ignore = TRUE; 753189251Ssam return NULL; 754189251Ssam } 755189251Ssam 756189251Ssam pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, &left); 757189251Ssam if (pos == NULL) { 758189251Ssam ret->ignore = TRUE; 759189251Ssam return NULL; 760189251Ssam } 761189251Ssam if (left == 0) { 762189251Ssam wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags " 763189251Ssam "octet included"); 764189251Ssam if (!sm->workaround) { 765189251Ssam ret->ignore = TRUE; 766189251Ssam return NULL; 767189251Ssam } 768189251Ssam 769189251Ssam wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags " 770189251Ssam "indicates ACK frame"); 771189251Ssam *flags = 0; 772189251Ssam } else { 773189251Ssam *flags = *pos++; 774189251Ssam left--; 775189251Ssam } 776189251Ssam wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - " 777189251Ssam "Flags 0x%02x", (unsigned long) wpabuf_len(reqData), 778189251Ssam *flags); 779189251Ssam if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { 780189251Ssam if (left < 4) { 781189251Ssam wpa_printf(MSG_INFO, "SSL: Short frame with TLS " 782189251Ssam "length"); 783189251Ssam ret->ignore = TRUE; 784189251Ssam return NULL; 785189251Ssam } 786189251Ssam tls_msg_len = WPA_GET_BE32(pos); 787189251Ssam wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", 788189251Ssam tls_msg_len); 789189251Ssam if (data->tls_in_left == 0) { 790189251Ssam data->tls_in_total = tls_msg_len; 791189251Ssam data->tls_in_left = tls_msg_len; 792214734Srpaulo wpabuf_free(data->tls_in); 793189251Ssam data->tls_in = NULL; 794189251Ssam } 795189251Ssam pos += 4; 796189251Ssam left -= 4; 797189251Ssam } 798189251Ssam 799189251Ssam ret->ignore = FALSE; 800189251Ssam ret->methodState = METHOD_MAY_CONT; 801189251Ssam ret->decision = DECISION_FAIL; 802189251Ssam ret->allowNotifications = TRUE; 803189251Ssam 804189251Ssam *len = left; 805189251Ssam return pos; 806189251Ssam} 807189251Ssam 808189251Ssam 809189251Ssam/** 810189251Ssam * eap_peer_tls_reset_input - Reset input buffers 811189251Ssam * @data: Data for TLS processing 812189251Ssam * 813189251Ssam * This function frees any allocated memory for input buffers and resets input 814189251Ssam * state. 815189251Ssam */ 816189251Ssamvoid eap_peer_tls_reset_input(struct eap_ssl_data *data) 817189251Ssam{ 818214734Srpaulo data->tls_in_left = data->tls_in_total = 0; 819214734Srpaulo wpabuf_free(data->tls_in); 820189251Ssam data->tls_in = NULL; 821189251Ssam} 822189251Ssam 823189251Ssam 824189251Ssam/** 825189251Ssam * eap_peer_tls_reset_output - Reset output buffers 826189251Ssam * @data: Data for TLS processing 827189251Ssam * 828189251Ssam * This function frees any allocated memory for output buffers and resets 829189251Ssam * output state. 830189251Ssam */ 831189251Ssamvoid eap_peer_tls_reset_output(struct eap_ssl_data *data) 832189251Ssam{ 833189251Ssam data->tls_out_pos = 0; 834214734Srpaulo wpabuf_free(data->tls_out); 835189251Ssam data->tls_out = NULL; 836189251Ssam} 837189251Ssam 838189251Ssam 839189251Ssam/** 840189251Ssam * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message 841189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 842189251Ssam * @data: Data for TLS processing 843189251Ssam * @in_data: Message received from the server 844189251Ssam * @in_decrypted: Buffer for returning a pointer to the decrypted message 845189251Ssam * Returns: 0 on success, 1 if more input data is needed, or -1 on failure 846189251Ssam */ 847189251Ssamint eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, 848189251Ssam const struct wpabuf *in_data, 849189251Ssam struct wpabuf **in_decrypted) 850189251Ssam{ 851214734Srpaulo const struct wpabuf *msg; 852189251Ssam int need_more_input; 853189251Ssam 854214734Srpaulo msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); 855189251Ssam if (msg == NULL) 856189251Ssam return need_more_input ? 1 : -1; 857189251Ssam 858214734Srpaulo *in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg); 859214734Srpaulo eap_peer_tls_reset_input(data); 860189251Ssam if (*in_decrypted == NULL) { 861189251Ssam wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data"); 862189251Ssam return -1; 863189251Ssam } 864189251Ssam return 0; 865189251Ssam} 866189251Ssam 867189251Ssam 868189251Ssam/** 869189251Ssam * eap_peer_tls_encrypt - Encrypt phase 2 TLS message 870189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 871189251Ssam * @data: Data for TLS processing 872189251Ssam * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 873189251Ssam * @peap_version: Version number for EAP-PEAP/TTLS 874189251Ssam * @id: EAP identifier for the response 875189251Ssam * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments 876189251Ssam * @out_data: Buffer for returning a pointer to the encrypted response message 877189251Ssam * Returns: 0 on success, -1 on failure 878189251Ssam */ 879189251Ssamint eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, 880189251Ssam EapType eap_type, int peap_version, u8 id, 881189251Ssam const struct wpabuf *in_data, 882189251Ssam struct wpabuf **out_data) 883189251Ssam{ 884189251Ssam if (in_data) { 885189251Ssam eap_peer_tls_reset_output(data); 886214734Srpaulo data->tls_out = tls_connection_encrypt(sm->ssl_ctx, data->conn, 887214734Srpaulo in_data); 888214734Srpaulo if (data->tls_out == NULL) { 889189251Ssam wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 " 890189251Ssam "data (in_len=%lu)", 891189251Ssam (unsigned long) wpabuf_len(in_data)); 892189251Ssam eap_peer_tls_reset_output(data); 893189251Ssam return -1; 894189251Ssam } 895189251Ssam } 896189251Ssam 897189251Ssam return eap_tls_process_output(data, eap_type, peap_version, id, 0, 898189251Ssam out_data); 899189251Ssam} 900189251Ssam 901189251Ssam 902189251Ssam/** 903189251Ssam * eap_peer_select_phase2_methods - Select phase 2 EAP method 904189251Ssam * @config: Pointer to the network configuration 905189251Ssam * @prefix: 'phase2' configuration prefix, e.g., "auth=" 906189251Ssam * @types: Buffer for returning allocated list of allowed EAP methods 907189251Ssam * @num_types: Buffer for returning number of allocated EAP methods 908189251Ssam * Returns: 0 on success, -1 on failure 909189251Ssam * 910189251Ssam * This function is used to parse EAP method list and select allowed methods 911189251Ssam * for Phase2 authentication. 912189251Ssam */ 913189251Ssamint eap_peer_select_phase2_methods(struct eap_peer_config *config, 914189251Ssam const char *prefix, 915189251Ssam struct eap_method_type **types, 916189251Ssam size_t *num_types) 917189251Ssam{ 918189251Ssam char *start, *pos, *buf; 919189251Ssam struct eap_method_type *methods = NULL, *_methods; 920189251Ssam u8 method; 921189251Ssam size_t num_methods = 0, prefix_len; 922189251Ssam 923189251Ssam if (config == NULL || config->phase2 == NULL) 924189251Ssam goto get_defaults; 925189251Ssam 926189251Ssam start = buf = os_strdup(config->phase2); 927189251Ssam if (buf == NULL) 928189251Ssam return -1; 929189251Ssam 930189251Ssam prefix_len = os_strlen(prefix); 931189251Ssam 932189251Ssam while (start && *start != '\0') { 933189251Ssam int vendor; 934189251Ssam pos = os_strstr(start, prefix); 935189251Ssam if (pos == NULL) 936189251Ssam break; 937189251Ssam if (start != pos && *(pos - 1) != ' ') { 938189251Ssam start = pos + prefix_len; 939189251Ssam continue; 940189251Ssam } 941189251Ssam 942189251Ssam start = pos + prefix_len; 943189251Ssam pos = os_strchr(start, ' '); 944189251Ssam if (pos) 945189251Ssam *pos++ = '\0'; 946189251Ssam method = eap_get_phase2_type(start, &vendor); 947189251Ssam if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { 948189251Ssam wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " 949189251Ssam "method '%s'", start); 950189251Ssam } else { 951189251Ssam num_methods++; 952189251Ssam _methods = os_realloc(methods, 953189251Ssam num_methods * sizeof(*methods)); 954189251Ssam if (_methods == NULL) { 955189251Ssam os_free(methods); 956189251Ssam os_free(buf); 957189251Ssam return -1; 958189251Ssam } 959189251Ssam methods = _methods; 960189251Ssam methods[num_methods - 1].vendor = vendor; 961189251Ssam methods[num_methods - 1].method = method; 962189251Ssam } 963189251Ssam 964189251Ssam start = pos; 965189251Ssam } 966189251Ssam 967189251Ssam os_free(buf); 968189251Ssam 969189251Ssamget_defaults: 970189251Ssam if (methods == NULL) 971189251Ssam methods = eap_get_phase2_types(config, &num_methods); 972189251Ssam 973189251Ssam if (methods == NULL) { 974189251Ssam wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available"); 975189251Ssam return -1; 976189251Ssam } 977189251Ssam wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types", 978189251Ssam (u8 *) methods, 979189251Ssam num_methods * sizeof(struct eap_method_type)); 980189251Ssam 981189251Ssam *types = methods; 982189251Ssam *num_types = num_methods; 983189251Ssam 984189251Ssam return 0; 985189251Ssam} 986189251Ssam 987189251Ssam 988189251Ssam/** 989189251Ssam * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2 990189251Ssam * @types: Buffer for returning allocated list of allowed EAP methods 991189251Ssam * @num_types: Buffer for returning number of allocated EAP methods 992189251Ssam * @hdr: EAP-Request header (and the following EAP type octet) 993189251Ssam * @resp: Buffer for returning the EAP-Nak message 994189251Ssam * Returns: 0 on success, -1 on failure 995189251Ssam */ 996189251Ssamint eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, 997189251Ssam struct eap_hdr *hdr, struct wpabuf **resp) 998189251Ssam{ 999189251Ssam u8 *pos = (u8 *) (hdr + 1); 1000189251Ssam size_t i; 1001189251Ssam 1002189251Ssam /* TODO: add support for expanded Nak */ 1003189251Ssam wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos); 1004189251Ssam wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types", 1005189251Ssam (u8 *) types, num_types * sizeof(struct eap_method_type)); 1006189251Ssam *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types, 1007189251Ssam EAP_CODE_RESPONSE, hdr->identifier); 1008189251Ssam if (*resp == NULL) 1009189251Ssam return -1; 1010189251Ssam 1011189251Ssam for (i = 0; i < num_types; i++) { 1012189251Ssam if (types[i].vendor == EAP_VENDOR_IETF && 1013189251Ssam types[i].method < 256) 1014189251Ssam wpabuf_put_u8(*resp, types[i].method); 1015189251Ssam } 1016189251Ssam 1017189251Ssam eap_update_len(*resp); 1018189251Ssam 1019189251Ssam return 0; 1020189251Ssam} 1021