ieee802_1x.c revision 214501
1214501Srpaulo/* 2214501Srpaulo * hostapd / IEEE 802.1X-2004 Authenticator 3214501Srpaulo * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5214501Srpaulo * This program is free software; you can redistribute it and/or modify 6214501Srpaulo * it under the terms of the GNU General Public License version 2 as 7214501Srpaulo * published by the Free Software Foundation. 8214501Srpaulo * 9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10214501Srpaulo * license. 11214501Srpaulo * 12214501Srpaulo * See README and COPYING for more details. 13214501Srpaulo */ 14214501Srpaulo 15214501Srpaulo#include "utils/includes.h" 16214501Srpaulo 17214501Srpaulo#include "utils/common.h" 18214501Srpaulo#include "utils/eloop.h" 19214501Srpaulo#include "crypto/md5.h" 20214501Srpaulo#include "crypto/crypto.h" 21214501Srpaulo#include "common/ieee802_11_defs.h" 22214501Srpaulo#include "common/wpa_ctrl.h" 23214501Srpaulo#include "radius/radius.h" 24214501Srpaulo#include "radius/radius_client.h" 25214501Srpaulo#include "eap_server/eap.h" 26214501Srpaulo#include "eap_common/eap_wsc_common.h" 27214501Srpaulo#include "eapol_auth/eapol_auth_sm.h" 28214501Srpaulo#include "eapol_auth/eapol_auth_sm_i.h" 29214501Srpaulo#include "hostapd.h" 30214501Srpaulo#include "accounting.h" 31214501Srpaulo#include "sta_info.h" 32214501Srpaulo#include "wpa_auth.h" 33214501Srpaulo#include "preauth_auth.h" 34214501Srpaulo#include "pmksa_cache_auth.h" 35214501Srpaulo#include "ap_config.h" 36214501Srpaulo#include "ieee802_1x.h" 37214501Srpaulo 38214501Srpaulo 39214501Srpaulostatic void ieee802_1x_finished(struct hostapd_data *hapd, 40214501Srpaulo struct sta_info *sta, int success); 41214501Srpaulo 42214501Srpaulo 43214501Srpaulostatic void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, 44214501Srpaulo u8 type, const u8 *data, size_t datalen) 45214501Srpaulo{ 46214501Srpaulo u8 *buf; 47214501Srpaulo struct ieee802_1x_hdr *xhdr; 48214501Srpaulo size_t len; 49214501Srpaulo int encrypt = 0; 50214501Srpaulo 51214501Srpaulo len = sizeof(*xhdr) + datalen; 52214501Srpaulo buf = os_zalloc(len); 53214501Srpaulo if (buf == NULL) { 54214501Srpaulo wpa_printf(MSG_ERROR, "malloc() failed for " 55214501Srpaulo "ieee802_1x_send(len=%lu)", 56214501Srpaulo (unsigned long) len); 57214501Srpaulo return; 58214501Srpaulo } 59214501Srpaulo 60214501Srpaulo xhdr = (struct ieee802_1x_hdr *) buf; 61214501Srpaulo xhdr->version = hapd->conf->eapol_version; 62214501Srpaulo xhdr->type = type; 63214501Srpaulo xhdr->length = host_to_be16(datalen); 64214501Srpaulo 65214501Srpaulo if (datalen > 0 && data != NULL) 66214501Srpaulo os_memcpy(xhdr + 1, data, datalen); 67214501Srpaulo 68214501Srpaulo if (wpa_auth_pairwise_set(sta->wpa_sm)) 69214501Srpaulo encrypt = 1; 70214501Srpaulo if (sta->flags & WLAN_STA_PREAUTH) { 71214501Srpaulo rsn_preauth_send(hapd, sta, buf, len); 72214501Srpaulo } else { 73214501Srpaulo hapd->drv.send_eapol(hapd, sta->addr, buf, len, encrypt); 74214501Srpaulo } 75214501Srpaulo 76214501Srpaulo os_free(buf); 77214501Srpaulo} 78214501Srpaulo 79214501Srpaulo 80214501Srpaulovoid ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, 81214501Srpaulo struct sta_info *sta, int authorized) 82214501Srpaulo{ 83214501Srpaulo int res; 84214501Srpaulo 85214501Srpaulo if (sta->flags & WLAN_STA_PREAUTH) 86214501Srpaulo return; 87214501Srpaulo 88214501Srpaulo if (authorized) { 89214501Srpaulo if (!(sta->flags & WLAN_STA_AUTHORIZED)) 90214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, 91214501Srpaulo AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); 92214501Srpaulo sta->flags |= WLAN_STA_AUTHORIZED; 93214501Srpaulo res = hapd->drv.set_authorized(hapd, sta, 1); 94214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 95214501Srpaulo HOSTAPD_LEVEL_DEBUG, "authorizing port"); 96214501Srpaulo } else { 97214501Srpaulo if ((sta->flags & (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC)) == 98214501Srpaulo (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC)) 99214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, 100214501Srpaulo AP_STA_DISCONNECTED MACSTR, 101214501Srpaulo MAC2STR(sta->addr)); 102214501Srpaulo sta->flags &= ~WLAN_STA_AUTHORIZED; 103214501Srpaulo res = hapd->drv.set_authorized(hapd, sta, 0); 104214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 105214501Srpaulo HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); 106214501Srpaulo } 107214501Srpaulo 108214501Srpaulo if (res && errno != ENOENT) { 109214501Srpaulo printf("Could not set station " MACSTR " flags for kernel " 110214501Srpaulo "driver (errno=%d).\n", MAC2STR(sta->addr), errno); 111214501Srpaulo } 112214501Srpaulo 113214501Srpaulo if (authorized) 114214501Srpaulo accounting_sta_start(hapd, sta); 115214501Srpaulo} 116214501Srpaulo 117214501Srpaulo 118214501Srpaulostatic void ieee802_1x_tx_key_one(struct hostapd_data *hapd, 119214501Srpaulo struct sta_info *sta, 120214501Srpaulo int idx, int broadcast, 121214501Srpaulo u8 *key_data, size_t key_len) 122214501Srpaulo{ 123214501Srpaulo u8 *buf, *ekey; 124214501Srpaulo struct ieee802_1x_hdr *hdr; 125214501Srpaulo struct ieee802_1x_eapol_key *key; 126214501Srpaulo size_t len, ekey_len; 127214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 128214501Srpaulo 129214501Srpaulo if (sm == NULL) 130214501Srpaulo return; 131214501Srpaulo 132214501Srpaulo len = sizeof(*key) + key_len; 133214501Srpaulo buf = os_zalloc(sizeof(*hdr) + len); 134214501Srpaulo if (buf == NULL) 135214501Srpaulo return; 136214501Srpaulo 137214501Srpaulo hdr = (struct ieee802_1x_hdr *) buf; 138214501Srpaulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 139214501Srpaulo key->type = EAPOL_KEY_TYPE_RC4; 140214501Srpaulo key->key_length = htons(key_len); 141214501Srpaulo wpa_get_ntp_timestamp(key->replay_counter); 142214501Srpaulo 143214501Srpaulo if (os_get_random(key->key_iv, sizeof(key->key_iv))) { 144214501Srpaulo wpa_printf(MSG_ERROR, "Could not get random numbers"); 145214501Srpaulo os_free(buf); 146214501Srpaulo return; 147214501Srpaulo } 148214501Srpaulo 149214501Srpaulo key->key_index = idx | (broadcast ? 0 : BIT(7)); 150214501Srpaulo if (hapd->conf->eapol_key_index_workaround) { 151214501Srpaulo /* According to some information, WinXP Supplicant seems to 152214501Srpaulo * interpret bit7 as an indication whether the key is to be 153214501Srpaulo * activated, so make it possible to enable workaround that 154214501Srpaulo * sets this bit for all keys. */ 155214501Srpaulo key->key_index |= BIT(7); 156214501Srpaulo } 157214501Srpaulo 158214501Srpaulo /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and 159214501Srpaulo * MSK[32..63] is used to sign the message. */ 160214501Srpaulo if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) { 161214501Srpaulo wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting " 162214501Srpaulo "and signing EAPOL-Key"); 163214501Srpaulo os_free(buf); 164214501Srpaulo return; 165214501Srpaulo } 166214501Srpaulo os_memcpy((u8 *) (key + 1), key_data, key_len); 167214501Srpaulo ekey_len = sizeof(key->key_iv) + 32; 168214501Srpaulo ekey = os_malloc(ekey_len); 169214501Srpaulo if (ekey == NULL) { 170214501Srpaulo wpa_printf(MSG_ERROR, "Could not encrypt key"); 171214501Srpaulo os_free(buf); 172214501Srpaulo return; 173214501Srpaulo } 174214501Srpaulo os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); 175214501Srpaulo os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); 176214501Srpaulo rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); 177214501Srpaulo os_free(ekey); 178214501Srpaulo 179214501Srpaulo /* This header is needed here for HMAC-MD5, but it will be regenerated 180214501Srpaulo * in ieee802_1x_send() */ 181214501Srpaulo hdr->version = hapd->conf->eapol_version; 182214501Srpaulo hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; 183214501Srpaulo hdr->length = host_to_be16(len); 184214501Srpaulo hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len, 185214501Srpaulo key->key_signature); 186214501Srpaulo 187214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR 188214501Srpaulo " (%s index=%d)", MAC2STR(sm->addr), 189214501Srpaulo broadcast ? "broadcast" : "unicast", idx); 190214501Srpaulo ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); 191214501Srpaulo if (sta->eapol_sm) 192214501Srpaulo sta->eapol_sm->dot1xAuthEapolFramesTx++; 193214501Srpaulo os_free(buf); 194214501Srpaulo} 195214501Srpaulo 196214501Srpaulo 197214501Srpaulo#ifndef CONFIG_NO_VLAN 198214501Srpaulostatic struct hostapd_wep_keys * 199214501Srpauloieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname) 200214501Srpaulo{ 201214501Srpaulo struct hostapd_wep_keys *key; 202214501Srpaulo 203214501Srpaulo key = os_zalloc(sizeof(*key)); 204214501Srpaulo if (key == NULL) 205214501Srpaulo return NULL; 206214501Srpaulo 207214501Srpaulo key->default_len = hapd->conf->default_wep_key_len; 208214501Srpaulo 209214501Srpaulo if (key->idx >= hapd->conf->broadcast_key_idx_max || 210214501Srpaulo key->idx < hapd->conf->broadcast_key_idx_min) 211214501Srpaulo key->idx = hapd->conf->broadcast_key_idx_min; 212214501Srpaulo else 213214501Srpaulo key->idx++; 214214501Srpaulo 215214501Srpaulo if (!key->key[key->idx]) 216214501Srpaulo key->key[key->idx] = os_malloc(key->default_len); 217214501Srpaulo if (key->key[key->idx] == NULL || 218214501Srpaulo os_get_random(key->key[key->idx], key->default_len)) { 219214501Srpaulo printf("Could not generate random WEP key (dynamic VLAN).\n"); 220214501Srpaulo os_free(key->key[key->idx]); 221214501Srpaulo key->key[key->idx] = NULL; 222214501Srpaulo os_free(key); 223214501Srpaulo return NULL; 224214501Srpaulo } 225214501Srpaulo key->len[key->idx] = key->default_len; 226214501Srpaulo 227214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Default WEP idx %d for dynamic VLAN\n", 228214501Srpaulo ifname, key->idx); 229214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)", 230214501Srpaulo key->key[key->idx], key->len[key->idx]); 231214501Srpaulo 232214501Srpaulo if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL, key->idx, 1, 233214501Srpaulo NULL, 0, key->key[key->idx], key->len[key->idx])) 234214501Srpaulo printf("Could not set dynamic VLAN WEP encryption key.\n"); 235214501Srpaulo 236214501Srpaulo hapd->drv.set_drv_ieee8021x(hapd, ifname, 1); 237214501Srpaulo 238214501Srpaulo return key; 239214501Srpaulo} 240214501Srpaulo 241214501Srpaulo 242214501Srpaulostatic struct hostapd_wep_keys * 243214501Srpauloieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid, 244214501Srpaulo size_t vlan_id) 245214501Srpaulo{ 246214501Srpaulo const char *ifname; 247214501Srpaulo 248214501Srpaulo if (vlan_id == 0) 249214501Srpaulo return &ssid->wep; 250214501Srpaulo 251214501Srpaulo if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys && 252214501Srpaulo ssid->dyn_vlan_keys[vlan_id]) 253214501Srpaulo return ssid->dyn_vlan_keys[vlan_id]; 254214501Srpaulo 255214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Creating new group " 256214501Srpaulo "state machine for VLAN ID %lu", 257214501Srpaulo (unsigned long) vlan_id); 258214501Srpaulo 259214501Srpaulo ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id); 260214501Srpaulo if (ifname == NULL) { 261214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Unknown VLAN ID %lu - " 262214501Srpaulo "cannot create group key state machine", 263214501Srpaulo (unsigned long) vlan_id); 264214501Srpaulo return NULL; 265214501Srpaulo } 266214501Srpaulo 267214501Srpaulo if (ssid->dyn_vlan_keys == NULL) { 268214501Srpaulo int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]); 269214501Srpaulo ssid->dyn_vlan_keys = os_zalloc(size); 270214501Srpaulo if (ssid->dyn_vlan_keys == NULL) 271214501Srpaulo return NULL; 272214501Srpaulo ssid->max_dyn_vlan_keys = vlan_id; 273214501Srpaulo } 274214501Srpaulo 275214501Srpaulo if (ssid->max_dyn_vlan_keys < vlan_id) { 276214501Srpaulo struct hostapd_wep_keys **na; 277214501Srpaulo int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]); 278214501Srpaulo na = os_realloc(ssid->dyn_vlan_keys, size); 279214501Srpaulo if (na == NULL) 280214501Srpaulo return NULL; 281214501Srpaulo ssid->dyn_vlan_keys = na; 282214501Srpaulo os_memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0, 283214501Srpaulo (vlan_id - ssid->max_dyn_vlan_keys) * 284214501Srpaulo sizeof(ssid->dyn_vlan_keys[0])); 285214501Srpaulo ssid->max_dyn_vlan_keys = vlan_id; 286214501Srpaulo } 287214501Srpaulo 288214501Srpaulo ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname); 289214501Srpaulo 290214501Srpaulo return ssid->dyn_vlan_keys[vlan_id]; 291214501Srpaulo} 292214501Srpaulo#endif /* CONFIG_NO_VLAN */ 293214501Srpaulo 294214501Srpaulo 295214501Srpaulovoid ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) 296214501Srpaulo{ 297214501Srpaulo struct eapol_authenticator *eapol = hapd->eapol_auth; 298214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 299214501Srpaulo#ifndef CONFIG_NO_VLAN 300214501Srpaulo struct hostapd_wep_keys *key = NULL; 301214501Srpaulo int vlan_id; 302214501Srpaulo#endif /* CONFIG_NO_VLAN */ 303214501Srpaulo 304214501Srpaulo if (sm == NULL || !sm->eap_if->eapKeyData) 305214501Srpaulo return; 306214501Srpaulo 307214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, 308214501Srpaulo MAC2STR(sta->addr)); 309214501Srpaulo 310214501Srpaulo#ifndef CONFIG_NO_VLAN 311214501Srpaulo vlan_id = sta->vlan_id; 312214501Srpaulo if (vlan_id < 0 || vlan_id > MAX_VLAN_ID) 313214501Srpaulo vlan_id = 0; 314214501Srpaulo 315214501Srpaulo if (vlan_id) { 316214501Srpaulo key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id); 317214501Srpaulo if (key && key->key[key->idx]) 318214501Srpaulo ieee802_1x_tx_key_one(hapd, sta, key->idx, 1, 319214501Srpaulo key->key[key->idx], 320214501Srpaulo key->len[key->idx]); 321214501Srpaulo } else 322214501Srpaulo#endif /* CONFIG_NO_VLAN */ 323214501Srpaulo if (eapol->default_wep_key) { 324214501Srpaulo ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, 325214501Srpaulo eapol->default_wep_key, 326214501Srpaulo hapd->conf->default_wep_key_len); 327214501Srpaulo } 328214501Srpaulo 329214501Srpaulo if (hapd->conf->individual_wep_key_len > 0) { 330214501Srpaulo u8 *ikey; 331214501Srpaulo ikey = os_malloc(hapd->conf->individual_wep_key_len); 332214501Srpaulo if (ikey == NULL || 333214501Srpaulo os_get_random(ikey, hapd->conf->individual_wep_key_len)) { 334214501Srpaulo wpa_printf(MSG_ERROR, "Could not generate random " 335214501Srpaulo "individual WEP key."); 336214501Srpaulo os_free(ikey); 337214501Srpaulo return; 338214501Srpaulo } 339214501Srpaulo 340214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", 341214501Srpaulo ikey, hapd->conf->individual_wep_key_len); 342214501Srpaulo 343214501Srpaulo ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, 344214501Srpaulo hapd->conf->individual_wep_key_len); 345214501Srpaulo 346214501Srpaulo /* TODO: set encryption in TX callback, i.e., only after STA 347214501Srpaulo * has ACKed EAPOL-Key frame */ 348214501Srpaulo if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 349214501Srpaulo sta->addr, 0, 1, NULL, 0, ikey, 350214501Srpaulo hapd->conf->individual_wep_key_len)) { 351214501Srpaulo wpa_printf(MSG_ERROR, "Could not set individual WEP " 352214501Srpaulo "encryption."); 353214501Srpaulo } 354214501Srpaulo 355214501Srpaulo os_free(ikey); 356214501Srpaulo } 357214501Srpaulo} 358214501Srpaulo 359214501Srpaulo 360214501Srpauloconst char *radius_mode_txt(struct hostapd_data *hapd) 361214501Srpaulo{ 362214501Srpaulo switch (hapd->iface->conf->hw_mode) { 363214501Srpaulo case HOSTAPD_MODE_IEEE80211A: 364214501Srpaulo return "802.11a"; 365214501Srpaulo case HOSTAPD_MODE_IEEE80211G: 366214501Srpaulo return "802.11g"; 367214501Srpaulo case HOSTAPD_MODE_IEEE80211B: 368214501Srpaulo default: 369214501Srpaulo return "802.11b"; 370214501Srpaulo } 371214501Srpaulo} 372214501Srpaulo 373214501Srpaulo 374214501Srpauloint radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) 375214501Srpaulo{ 376214501Srpaulo int i; 377214501Srpaulo u8 rate = 0; 378214501Srpaulo 379214501Srpaulo for (i = 0; i < sta->supported_rates_len; i++) 380214501Srpaulo if ((sta->supported_rates[i] & 0x7f) > rate) 381214501Srpaulo rate = sta->supported_rates[i] & 0x7f; 382214501Srpaulo 383214501Srpaulo return rate; 384214501Srpaulo} 385214501Srpaulo 386214501Srpaulo 387214501Srpaulo#ifndef CONFIG_NO_RADIUS 388214501Srpaulostatic void ieee802_1x_learn_identity(struct hostapd_data *hapd, 389214501Srpaulo struct eapol_state_machine *sm, 390214501Srpaulo const u8 *eap, size_t len) 391214501Srpaulo{ 392214501Srpaulo const u8 *identity; 393214501Srpaulo size_t identity_len; 394214501Srpaulo 395214501Srpaulo if (len <= sizeof(struct eap_hdr) || 396214501Srpaulo eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) 397214501Srpaulo return; 398214501Srpaulo 399214501Srpaulo identity = eap_get_identity(sm->eap, &identity_len); 400214501Srpaulo if (identity == NULL) 401214501Srpaulo return; 402214501Srpaulo 403214501Srpaulo /* Save station identity for future RADIUS packets */ 404214501Srpaulo os_free(sm->identity); 405214501Srpaulo sm->identity = os_malloc(identity_len + 1); 406214501Srpaulo if (sm->identity == NULL) { 407214501Srpaulo sm->identity_len = 0; 408214501Srpaulo return; 409214501Srpaulo } 410214501Srpaulo 411214501Srpaulo os_memcpy(sm->identity, identity, identity_len); 412214501Srpaulo sm->identity_len = identity_len; 413214501Srpaulo sm->identity[identity_len] = '\0'; 414214501Srpaulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 415214501Srpaulo HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity); 416214501Srpaulo sm->dot1xAuthEapolRespIdFramesRx++; 417214501Srpaulo} 418214501Srpaulo 419214501Srpaulo 420214501Srpaulostatic void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, 421214501Srpaulo struct sta_info *sta, 422214501Srpaulo const u8 *eap, size_t len) 423214501Srpaulo{ 424214501Srpaulo struct radius_msg *msg; 425214501Srpaulo char buf[128]; 426214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 427214501Srpaulo 428214501Srpaulo if (sm == NULL) 429214501Srpaulo return; 430214501Srpaulo 431214501Srpaulo ieee802_1x_learn_identity(hapd, sm, eap, len); 432214501Srpaulo 433214501Srpaulo wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " 434214501Srpaulo "packet"); 435214501Srpaulo 436214501Srpaulo sm->radius_identifier = radius_client_get_id(hapd->radius); 437214501Srpaulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, 438214501Srpaulo sm->radius_identifier); 439214501Srpaulo if (msg == NULL) { 440214501Srpaulo printf("Could not create net RADIUS packet\n"); 441214501Srpaulo return; 442214501Srpaulo } 443214501Srpaulo 444214501Srpaulo radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta)); 445214501Srpaulo 446214501Srpaulo if (sm->identity && 447214501Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, 448214501Srpaulo sm->identity, sm->identity_len)) { 449214501Srpaulo printf("Could not add User-Name\n"); 450214501Srpaulo goto fail; 451214501Srpaulo } 452214501Srpaulo 453214501Srpaulo if (hapd->conf->own_ip_addr.af == AF_INET && 454214501Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 455214501Srpaulo (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { 456214501Srpaulo printf("Could not add NAS-IP-Address\n"); 457214501Srpaulo goto fail; 458214501Srpaulo } 459214501Srpaulo 460214501Srpaulo#ifdef CONFIG_IPV6 461214501Srpaulo if (hapd->conf->own_ip_addr.af == AF_INET6 && 462214501Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 463214501Srpaulo (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { 464214501Srpaulo printf("Could not add NAS-IPv6-Address\n"); 465214501Srpaulo goto fail; 466214501Srpaulo } 467214501Srpaulo#endif /* CONFIG_IPV6 */ 468214501Srpaulo 469214501Srpaulo if (hapd->conf->nas_identifier && 470214501Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 471214501Srpaulo (u8 *) hapd->conf->nas_identifier, 472214501Srpaulo os_strlen(hapd->conf->nas_identifier))) { 473214501Srpaulo printf("Could not add NAS-Identifier\n"); 474214501Srpaulo goto fail; 475214501Srpaulo } 476214501Srpaulo 477214501Srpaulo if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { 478214501Srpaulo printf("Could not add NAS-Port\n"); 479214501Srpaulo goto fail; 480214501Srpaulo } 481214501Srpaulo 482214501Srpaulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", 483214501Srpaulo MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid); 484214501Srpaulo buf[sizeof(buf) - 1] = '\0'; 485214501Srpaulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, 486214501Srpaulo (u8 *) buf, os_strlen(buf))) { 487214501Srpaulo printf("Could not add Called-Station-Id\n"); 488214501Srpaulo goto fail; 489214501Srpaulo } 490214501Srpaulo 491214501Srpaulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 492214501Srpaulo MAC2STR(sta->addr)); 493214501Srpaulo buf[sizeof(buf) - 1] = '\0'; 494214501Srpaulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 495214501Srpaulo (u8 *) buf, os_strlen(buf))) { 496214501Srpaulo printf("Could not add Calling-Station-Id\n"); 497214501Srpaulo goto fail; 498214501Srpaulo } 499214501Srpaulo 500214501Srpaulo /* TODO: should probably check MTU from driver config; 2304 is max for 501214501Srpaulo * IEEE 802.11, but use 1400 to avoid problems with too large packets 502214501Srpaulo */ 503214501Srpaulo if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { 504214501Srpaulo printf("Could not add Framed-MTU\n"); 505214501Srpaulo goto fail; 506214501Srpaulo } 507214501Srpaulo 508214501Srpaulo if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, 509214501Srpaulo RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { 510214501Srpaulo printf("Could not add NAS-Port-Type\n"); 511214501Srpaulo goto fail; 512214501Srpaulo } 513214501Srpaulo 514214501Srpaulo if (sta->flags & WLAN_STA_PREAUTH) { 515214501Srpaulo os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", 516214501Srpaulo sizeof(buf)); 517214501Srpaulo } else { 518214501Srpaulo os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", 519214501Srpaulo radius_sta_rate(hapd, sta) / 2, 520214501Srpaulo (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", 521214501Srpaulo radius_mode_txt(hapd)); 522214501Srpaulo buf[sizeof(buf) - 1] = '\0'; 523214501Srpaulo } 524214501Srpaulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 525214501Srpaulo (u8 *) buf, os_strlen(buf))) { 526214501Srpaulo printf("Could not add Connect-Info\n"); 527214501Srpaulo goto fail; 528214501Srpaulo } 529214501Srpaulo 530214501Srpaulo if (eap && !radius_msg_add_eap(msg, eap, len)) { 531214501Srpaulo printf("Could not add EAP-Message\n"); 532214501Srpaulo goto fail; 533214501Srpaulo } 534214501Srpaulo 535214501Srpaulo /* State attribute must be copied if and only if this packet is 536214501Srpaulo * Access-Request reply to the previous Access-Challenge */ 537214501Srpaulo if (sm->last_recv_radius && 538214501Srpaulo radius_msg_get_hdr(sm->last_recv_radius)->code == 539214501Srpaulo RADIUS_CODE_ACCESS_CHALLENGE) { 540214501Srpaulo int res = radius_msg_copy_attr(msg, sm->last_recv_radius, 541214501Srpaulo RADIUS_ATTR_STATE); 542214501Srpaulo if (res < 0) { 543214501Srpaulo printf("Could not copy State attribute from previous " 544214501Srpaulo "Access-Challenge\n"); 545214501Srpaulo goto fail; 546214501Srpaulo } 547214501Srpaulo if (res > 0) { 548214501Srpaulo wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); 549214501Srpaulo } 550214501Srpaulo } 551214501Srpaulo 552214501Srpaulo radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr); 553214501Srpaulo return; 554214501Srpaulo 555214501Srpaulo fail: 556214501Srpaulo radius_msg_free(msg); 557214501Srpaulo} 558214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 559214501Srpaulo 560214501Srpaulo 561214501Srpaulostatic void handle_eap_response(struct hostapd_data *hapd, 562214501Srpaulo struct sta_info *sta, struct eap_hdr *eap, 563214501Srpaulo size_t len) 564214501Srpaulo{ 565214501Srpaulo u8 type, *data; 566214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 567214501Srpaulo if (sm == NULL) 568214501Srpaulo return; 569214501Srpaulo 570214501Srpaulo data = (u8 *) (eap + 1); 571214501Srpaulo 572214501Srpaulo if (len < sizeof(*eap) + 1) { 573214501Srpaulo printf("handle_eap_response: too short response data\n"); 574214501Srpaulo return; 575214501Srpaulo } 576214501Srpaulo 577214501Srpaulo sm->eap_type_supp = type = data[0]; 578214501Srpaulo 579214501Srpaulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 580214501Srpaulo HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 581214501Srpaulo "id=%d len=%d) from STA: EAP Response-%s (%d)", 582214501Srpaulo eap->code, eap->identifier, be_to_host16(eap->length), 583214501Srpaulo eap_server_get_name(0, type), type); 584214501Srpaulo 585214501Srpaulo sm->dot1xAuthEapolRespFramesRx++; 586214501Srpaulo 587214501Srpaulo wpabuf_free(sm->eap_if->eapRespData); 588214501Srpaulo sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 589214501Srpaulo sm->eapolEap = TRUE; 590214501Srpaulo} 591214501Srpaulo 592214501Srpaulo 593214501Srpaulo/* Process incoming EAP packet from Supplicant */ 594214501Srpaulostatic void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, 595214501Srpaulo u8 *buf, size_t len) 596214501Srpaulo{ 597214501Srpaulo struct eap_hdr *eap; 598214501Srpaulo u16 eap_len; 599214501Srpaulo 600214501Srpaulo if (len < sizeof(*eap)) { 601214501Srpaulo printf(" too short EAP packet\n"); 602214501Srpaulo return; 603214501Srpaulo } 604214501Srpaulo 605214501Srpaulo eap = (struct eap_hdr *) buf; 606214501Srpaulo 607214501Srpaulo eap_len = be_to_host16(eap->length); 608214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", 609214501Srpaulo eap->code, eap->identifier, eap_len); 610214501Srpaulo if (eap_len < sizeof(*eap)) { 611214501Srpaulo wpa_printf(MSG_DEBUG, " Invalid EAP length"); 612214501Srpaulo return; 613214501Srpaulo } else if (eap_len > len) { 614214501Srpaulo wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP " 615214501Srpaulo "packet"); 616214501Srpaulo return; 617214501Srpaulo } else if (eap_len < len) { 618214501Srpaulo wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP " 619214501Srpaulo "packet", (unsigned long) len - eap_len); 620214501Srpaulo } 621214501Srpaulo 622214501Srpaulo switch (eap->code) { 623214501Srpaulo case EAP_CODE_REQUEST: 624214501Srpaulo wpa_printf(MSG_DEBUG, " (request)"); 625214501Srpaulo return; 626214501Srpaulo case EAP_CODE_RESPONSE: 627214501Srpaulo wpa_printf(MSG_DEBUG, " (response)"); 628214501Srpaulo handle_eap_response(hapd, sta, eap, eap_len); 629214501Srpaulo break; 630214501Srpaulo case EAP_CODE_SUCCESS: 631214501Srpaulo wpa_printf(MSG_DEBUG, " (success)"); 632214501Srpaulo return; 633214501Srpaulo case EAP_CODE_FAILURE: 634214501Srpaulo wpa_printf(MSG_DEBUG, " (failure)"); 635214501Srpaulo return; 636214501Srpaulo default: 637214501Srpaulo wpa_printf(MSG_DEBUG, " (unknown code)"); 638214501Srpaulo return; 639214501Srpaulo } 640214501Srpaulo} 641214501Srpaulo 642214501Srpaulo 643214501Srpaulostatic struct eapol_state_machine * 644214501Srpauloieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) 645214501Srpaulo{ 646214501Srpaulo int flags = 0; 647214501Srpaulo if (sta->flags & WLAN_STA_PREAUTH) 648214501Srpaulo flags |= EAPOL_SM_PREAUTH; 649214501Srpaulo if (sta->wpa_sm) { 650214501Srpaulo flags |= EAPOL_SM_USES_WPA; 651214501Srpaulo if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) 652214501Srpaulo flags |= EAPOL_SM_FROM_PMKSA_CACHE; 653214501Srpaulo } 654214501Srpaulo return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, 655214501Srpaulo sta->wps_ie, sta); 656214501Srpaulo} 657214501Srpaulo 658214501Srpaulo 659214501Srpaulo/** 660214501Srpaulo * ieee802_1x_receive - Process the EAPOL frames from the Supplicant 661214501Srpaulo * @hapd: hostapd BSS data 662214501Srpaulo * @sa: Source address (sender of the EAPOL frame) 663214501Srpaulo * @buf: EAPOL frame 664214501Srpaulo * @len: Length of buf in octets 665214501Srpaulo * 666214501Srpaulo * This function is called for each incoming EAPOL frame from the interface 667214501Srpaulo */ 668214501Srpaulovoid ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, 669214501Srpaulo size_t len) 670214501Srpaulo{ 671214501Srpaulo struct sta_info *sta; 672214501Srpaulo struct ieee802_1x_hdr *hdr; 673214501Srpaulo struct ieee802_1x_eapol_key *key; 674214501Srpaulo u16 datalen; 675214501Srpaulo struct rsn_pmksa_cache_entry *pmksa; 676214501Srpaulo 677214501Srpaulo if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && 678214501Srpaulo !hapd->conf->wps_state) 679214501Srpaulo return; 680214501Srpaulo 681214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, 682214501Srpaulo (unsigned long) len, MAC2STR(sa)); 683214501Srpaulo sta = ap_get_sta(hapd, sa); 684214501Srpaulo if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { 685214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " 686214501Srpaulo "associated STA"); 687214501Srpaulo return; 688214501Srpaulo } 689214501Srpaulo 690214501Srpaulo if (len < sizeof(*hdr)) { 691214501Srpaulo printf(" too short IEEE 802.1X packet\n"); 692214501Srpaulo return; 693214501Srpaulo } 694214501Srpaulo 695214501Srpaulo hdr = (struct ieee802_1x_hdr *) buf; 696214501Srpaulo datalen = be_to_host16(hdr->length); 697214501Srpaulo wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", 698214501Srpaulo hdr->version, hdr->type, datalen); 699214501Srpaulo 700214501Srpaulo if (len - sizeof(*hdr) < datalen) { 701214501Srpaulo printf(" frame too short for this IEEE 802.1X packet\n"); 702214501Srpaulo if (sta->eapol_sm) 703214501Srpaulo sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; 704214501Srpaulo return; 705214501Srpaulo } 706214501Srpaulo if (len - sizeof(*hdr) > datalen) { 707214501Srpaulo wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " 708214501Srpaulo "IEEE 802.1X packet", 709214501Srpaulo (unsigned long) len - sizeof(*hdr) - datalen); 710214501Srpaulo } 711214501Srpaulo 712214501Srpaulo if (sta->eapol_sm) { 713214501Srpaulo sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; 714214501Srpaulo sta->eapol_sm->dot1xAuthEapolFramesRx++; 715214501Srpaulo } 716214501Srpaulo 717214501Srpaulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 718214501Srpaulo if (datalen >= sizeof(struct ieee802_1x_eapol_key) && 719214501Srpaulo hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && 720214501Srpaulo (key->type == EAPOL_KEY_TYPE_WPA || 721214501Srpaulo key->type == EAPOL_KEY_TYPE_RSN)) { 722214501Srpaulo wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, 723214501Srpaulo sizeof(*hdr) + datalen); 724214501Srpaulo return; 725214501Srpaulo } 726214501Srpaulo 727214501Srpaulo if ((!hapd->conf->ieee802_1x && 728214501Srpaulo !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) || 729214501Srpaulo wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm))) 730214501Srpaulo return; 731214501Srpaulo 732214501Srpaulo if (!sta->eapol_sm) { 733214501Srpaulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 734214501Srpaulo if (!sta->eapol_sm) 735214501Srpaulo return; 736214501Srpaulo 737214501Srpaulo#ifdef CONFIG_WPS 738214501Srpaulo if (!hapd->conf->ieee802_1x && 739214501Srpaulo ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == 740214501Srpaulo WLAN_STA_MAYBE_WPS)) { 741214501Srpaulo /* 742214501Srpaulo * Delay EAPOL frame transmission until a possible WPS 743214501Srpaulo * STA initiates the handshake with EAPOL-Start. 744214501Srpaulo */ 745214501Srpaulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 746214501Srpaulo } 747214501Srpaulo#endif /* CONFIG_WPS */ 748214501Srpaulo 749214501Srpaulo sta->eapol_sm->eap_if->portEnabled = TRUE; 750214501Srpaulo } 751214501Srpaulo 752214501Srpaulo /* since we support version 1, we can ignore version field and proceed 753214501Srpaulo * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ 754214501Srpaulo /* TODO: actually, we are not version 1 anymore.. However, Version 2 755214501Srpaulo * does not change frame contents, so should be ok to process frames 756214501Srpaulo * more or less identically. Some changes might be needed for 757214501Srpaulo * verification of fields. */ 758214501Srpaulo 759214501Srpaulo switch (hdr->type) { 760214501Srpaulo case IEEE802_1X_TYPE_EAP_PACKET: 761214501Srpaulo handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); 762214501Srpaulo break; 763214501Srpaulo 764214501Srpaulo case IEEE802_1X_TYPE_EAPOL_START: 765214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 766214501Srpaulo HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start " 767214501Srpaulo "from STA"); 768214501Srpaulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 769214501Srpaulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 770214501Srpaulo if (pmksa) { 771214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 772214501Srpaulo HOSTAPD_LEVEL_DEBUG, "cached PMKSA " 773214501Srpaulo "available - ignore it since " 774214501Srpaulo "STA sent EAPOL-Start"); 775214501Srpaulo wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); 776214501Srpaulo } 777214501Srpaulo sta->eapol_sm->eapolStart = TRUE; 778214501Srpaulo sta->eapol_sm->dot1xAuthEapolStartFramesRx++; 779214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 780214501Srpaulo break; 781214501Srpaulo 782214501Srpaulo case IEEE802_1X_TYPE_EAPOL_LOGOFF: 783214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 784214501Srpaulo HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff " 785214501Srpaulo "from STA"); 786214501Srpaulo sta->acct_terminate_cause = 787214501Srpaulo RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 788214501Srpaulo accounting_sta_stop(hapd, sta); 789214501Srpaulo sta->eapol_sm->eapolLogoff = TRUE; 790214501Srpaulo sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; 791214501Srpaulo break; 792214501Srpaulo 793214501Srpaulo case IEEE802_1X_TYPE_EAPOL_KEY: 794214501Srpaulo wpa_printf(MSG_DEBUG, " EAPOL-Key"); 795214501Srpaulo if (!(sta->flags & WLAN_STA_AUTHORIZED)) { 796214501Srpaulo wpa_printf(MSG_DEBUG, " Dropped key data from " 797214501Srpaulo "unauthorized Supplicant"); 798214501Srpaulo break; 799214501Srpaulo } 800214501Srpaulo break; 801214501Srpaulo 802214501Srpaulo case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: 803214501Srpaulo wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); 804214501Srpaulo /* TODO: implement support for this; show data */ 805214501Srpaulo break; 806214501Srpaulo 807214501Srpaulo default: 808214501Srpaulo wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); 809214501Srpaulo sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; 810214501Srpaulo break; 811214501Srpaulo } 812214501Srpaulo 813214501Srpaulo eapol_auth_step(sta->eapol_sm); 814214501Srpaulo} 815214501Srpaulo 816214501Srpaulo 817214501Srpaulo/** 818214501Srpaulo * ieee802_1x_new_station - Start IEEE 802.1X authentication 819214501Srpaulo * @hapd: hostapd BSS data 820214501Srpaulo * @sta: The station 821214501Srpaulo * 822214501Srpaulo * This function is called to start IEEE 802.1X authentication when a new 823214501Srpaulo * station completes IEEE 802.11 association. 824214501Srpaulo */ 825214501Srpaulovoid ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) 826214501Srpaulo{ 827214501Srpaulo struct rsn_pmksa_cache_entry *pmksa; 828214501Srpaulo int reassoc = 1; 829214501Srpaulo int force_1x = 0; 830214501Srpaulo 831214501Srpaulo#ifdef CONFIG_WPS 832214501Srpaulo if (hapd->conf->wps_state && hapd->conf->wpa && 833214501Srpaulo (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { 834214501Srpaulo /* 835214501Srpaulo * Need to enable IEEE 802.1X/EAPOL state machines for possible 836214501Srpaulo * WPS handshake even if IEEE 802.1X/EAPOL is not used for 837214501Srpaulo * authentication in this BSS. 838214501Srpaulo */ 839214501Srpaulo force_1x = 1; 840214501Srpaulo } 841214501Srpaulo#endif /* CONFIG_WPS */ 842214501Srpaulo 843214501Srpaulo if ((!force_1x && !hapd->conf->ieee802_1x) || 844214501Srpaulo wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm))) 845214501Srpaulo return; 846214501Srpaulo 847214501Srpaulo if (sta->eapol_sm == NULL) { 848214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 849214501Srpaulo HOSTAPD_LEVEL_DEBUG, "start authentication"); 850214501Srpaulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 851214501Srpaulo if (sta->eapol_sm == NULL) { 852214501Srpaulo hostapd_logger(hapd, sta->addr, 853214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 854214501Srpaulo HOSTAPD_LEVEL_INFO, 855214501Srpaulo "failed to allocate state machine"); 856214501Srpaulo return; 857214501Srpaulo } 858214501Srpaulo reassoc = 0; 859214501Srpaulo } 860214501Srpaulo 861214501Srpaulo#ifdef CONFIG_WPS 862214501Srpaulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 863214501Srpaulo if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) { 864214501Srpaulo /* 865214501Srpaulo * Delay EAPOL frame transmission until a possible WPS 866214501Srpaulo * initiates the handshake with EAPOL-Start. 867214501Srpaulo */ 868214501Srpaulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 869214501Srpaulo } 870214501Srpaulo#endif /* CONFIG_WPS */ 871214501Srpaulo 872214501Srpaulo sta->eapol_sm->eap_if->portEnabled = TRUE; 873214501Srpaulo 874214501Srpaulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 875214501Srpaulo if (pmksa) { 876214501Srpaulo int old_vlanid; 877214501Srpaulo 878214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 879214501Srpaulo HOSTAPD_LEVEL_DEBUG, 880214501Srpaulo "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); 881214501Srpaulo /* Setup EAPOL state machines to already authenticated state 882214501Srpaulo * because of existing PMKSA information in the cache. */ 883214501Srpaulo sta->eapol_sm->keyRun = TRUE; 884214501Srpaulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 885214501Srpaulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 886214501Srpaulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 887214501Srpaulo sta->eapol_sm->authSuccess = TRUE; 888214501Srpaulo if (sta->eapol_sm->eap) 889214501Srpaulo eap_sm_notify_cached(sta->eapol_sm->eap); 890214501Srpaulo old_vlanid = sta->vlan_id; 891214501Srpaulo pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm); 892214501Srpaulo if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) 893214501Srpaulo sta->vlan_id = 0; 894214501Srpaulo ap_sta_bind_vlan(hapd, sta, old_vlanid); 895214501Srpaulo } else { 896214501Srpaulo if (reassoc) { 897214501Srpaulo /* 898214501Srpaulo * Force EAPOL state machines to start 899214501Srpaulo * re-authentication without having to wait for the 900214501Srpaulo * Supplicant to send EAPOL-Start. 901214501Srpaulo */ 902214501Srpaulo sta->eapol_sm->reAuthenticate = TRUE; 903214501Srpaulo } 904214501Srpaulo eapol_auth_step(sta->eapol_sm); 905214501Srpaulo } 906214501Srpaulo} 907214501Srpaulo 908214501Srpaulo 909214501Srpaulovoid ieee802_1x_free_station(struct sta_info *sta) 910214501Srpaulo{ 911214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 912214501Srpaulo 913214501Srpaulo if (sm == NULL) 914214501Srpaulo return; 915214501Srpaulo 916214501Srpaulo sta->eapol_sm = NULL; 917214501Srpaulo 918214501Srpaulo#ifndef CONFIG_NO_RADIUS 919214501Srpaulo radius_msg_free(sm->last_recv_radius); 920214501Srpaulo radius_free_class(&sm->radius_class); 921214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 922214501Srpaulo 923214501Srpaulo os_free(sm->identity); 924214501Srpaulo eapol_auth_free(sm); 925214501Srpaulo} 926214501Srpaulo 927214501Srpaulo 928214501Srpaulo#ifndef CONFIG_NO_RADIUS 929214501Srpaulostatic void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, 930214501Srpaulo struct sta_info *sta) 931214501Srpaulo{ 932214501Srpaulo u8 *eap; 933214501Srpaulo size_t len; 934214501Srpaulo struct eap_hdr *hdr; 935214501Srpaulo int eap_type = -1; 936214501Srpaulo char buf[64]; 937214501Srpaulo struct radius_msg *msg; 938214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 939214501Srpaulo 940214501Srpaulo if (sm == NULL || sm->last_recv_radius == NULL) { 941214501Srpaulo if (sm) 942214501Srpaulo sm->eap_if->aaaEapNoReq = TRUE; 943214501Srpaulo return; 944214501Srpaulo } 945214501Srpaulo 946214501Srpaulo msg = sm->last_recv_radius; 947214501Srpaulo 948214501Srpaulo eap = radius_msg_get_eap(msg, &len); 949214501Srpaulo if (eap == NULL) { 950214501Srpaulo /* RFC 3579, Chap. 2.6.3: 951214501Srpaulo * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message 952214501Srpaulo * attribute */ 953214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 954214501Srpaulo HOSTAPD_LEVEL_WARNING, "could not extract " 955214501Srpaulo "EAP-Message from RADIUS message"); 956214501Srpaulo sm->eap_if->aaaEapNoReq = TRUE; 957214501Srpaulo return; 958214501Srpaulo } 959214501Srpaulo 960214501Srpaulo if (len < sizeof(*hdr)) { 961214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 962214501Srpaulo HOSTAPD_LEVEL_WARNING, "too short EAP packet " 963214501Srpaulo "received from authentication server"); 964214501Srpaulo os_free(eap); 965214501Srpaulo sm->eap_if->aaaEapNoReq = TRUE; 966214501Srpaulo return; 967214501Srpaulo } 968214501Srpaulo 969214501Srpaulo if (len > sizeof(*hdr)) 970214501Srpaulo eap_type = eap[sizeof(*hdr)]; 971214501Srpaulo 972214501Srpaulo hdr = (struct eap_hdr *) eap; 973214501Srpaulo switch (hdr->code) { 974214501Srpaulo case EAP_CODE_REQUEST: 975214501Srpaulo if (eap_type >= 0) 976214501Srpaulo sm->eap_type_authsrv = eap_type; 977214501Srpaulo os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", 978214501Srpaulo eap_type >= 0 ? eap_server_get_name(0, eap_type) : 979214501Srpaulo "??", 980214501Srpaulo eap_type); 981214501Srpaulo break; 982214501Srpaulo case EAP_CODE_RESPONSE: 983214501Srpaulo os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", 984214501Srpaulo eap_type >= 0 ? eap_server_get_name(0, eap_type) : 985214501Srpaulo "??", 986214501Srpaulo eap_type); 987214501Srpaulo break; 988214501Srpaulo case EAP_CODE_SUCCESS: 989214501Srpaulo os_strlcpy(buf, "EAP Success", sizeof(buf)); 990214501Srpaulo break; 991214501Srpaulo case EAP_CODE_FAILURE: 992214501Srpaulo os_strlcpy(buf, "EAP Failure", sizeof(buf)); 993214501Srpaulo break; 994214501Srpaulo default: 995214501Srpaulo os_strlcpy(buf, "unknown EAP code", sizeof(buf)); 996214501Srpaulo break; 997214501Srpaulo } 998214501Srpaulo buf[sizeof(buf) - 1] = '\0'; 999214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1000214501Srpaulo HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d " 1001214501Srpaulo "id=%d len=%d) from RADIUS server: %s", 1002214501Srpaulo hdr->code, hdr->identifier, be_to_host16(hdr->length), 1003214501Srpaulo buf); 1004214501Srpaulo sm->eap_if->aaaEapReq = TRUE; 1005214501Srpaulo 1006214501Srpaulo wpabuf_free(sm->eap_if->aaaEapReqData); 1007214501Srpaulo sm->eap_if->aaaEapReqData = wpabuf_alloc_ext_data(eap, len); 1008214501Srpaulo} 1009214501Srpaulo 1010214501Srpaulo 1011214501Srpaulostatic void ieee802_1x_get_keys(struct hostapd_data *hapd, 1012214501Srpaulo struct sta_info *sta, struct radius_msg *msg, 1013214501Srpaulo struct radius_msg *req, 1014214501Srpaulo const u8 *shared_secret, 1015214501Srpaulo size_t shared_secret_len) 1016214501Srpaulo{ 1017214501Srpaulo struct radius_ms_mppe_keys *keys; 1018214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1019214501Srpaulo if (sm == NULL) 1020214501Srpaulo return; 1021214501Srpaulo 1022214501Srpaulo keys = radius_msg_get_ms_keys(msg, req, shared_secret, 1023214501Srpaulo shared_secret_len); 1024214501Srpaulo 1025214501Srpaulo if (keys && keys->send && keys->recv) { 1026214501Srpaulo size_t len = keys->send_len + keys->recv_len; 1027214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", 1028214501Srpaulo keys->send, keys->send_len); 1029214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", 1030214501Srpaulo keys->recv, keys->recv_len); 1031214501Srpaulo 1032214501Srpaulo os_free(sm->eap_if->aaaEapKeyData); 1033214501Srpaulo sm->eap_if->aaaEapKeyData = os_malloc(len); 1034214501Srpaulo if (sm->eap_if->aaaEapKeyData) { 1035214501Srpaulo os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv, 1036214501Srpaulo keys->recv_len); 1037214501Srpaulo os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len, 1038214501Srpaulo keys->send, keys->send_len); 1039214501Srpaulo sm->eap_if->aaaEapKeyDataLen = len; 1040214501Srpaulo sm->eap_if->aaaEapKeyAvailable = TRUE; 1041214501Srpaulo } 1042214501Srpaulo } 1043214501Srpaulo 1044214501Srpaulo if (keys) { 1045214501Srpaulo os_free(keys->send); 1046214501Srpaulo os_free(keys->recv); 1047214501Srpaulo os_free(keys); 1048214501Srpaulo } 1049214501Srpaulo} 1050214501Srpaulo 1051214501Srpaulo 1052214501Srpaulostatic void ieee802_1x_store_radius_class(struct hostapd_data *hapd, 1053214501Srpaulo struct sta_info *sta, 1054214501Srpaulo struct radius_msg *msg) 1055214501Srpaulo{ 1056214501Srpaulo u8 *class; 1057214501Srpaulo size_t class_len; 1058214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1059214501Srpaulo int count, i; 1060214501Srpaulo struct radius_attr_data *nclass; 1061214501Srpaulo size_t nclass_count; 1062214501Srpaulo 1063214501Srpaulo if (!hapd->conf->radius->acct_server || hapd->radius == NULL || 1064214501Srpaulo sm == NULL) 1065214501Srpaulo return; 1066214501Srpaulo 1067214501Srpaulo radius_free_class(&sm->radius_class); 1068214501Srpaulo count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); 1069214501Srpaulo if (count <= 0) 1070214501Srpaulo return; 1071214501Srpaulo 1072214501Srpaulo nclass = os_zalloc(count * sizeof(struct radius_attr_data)); 1073214501Srpaulo if (nclass == NULL) 1074214501Srpaulo return; 1075214501Srpaulo 1076214501Srpaulo nclass_count = 0; 1077214501Srpaulo 1078214501Srpaulo class = NULL; 1079214501Srpaulo for (i = 0; i < count; i++) { 1080214501Srpaulo do { 1081214501Srpaulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, 1082214501Srpaulo &class, &class_len, 1083214501Srpaulo class) < 0) { 1084214501Srpaulo i = count; 1085214501Srpaulo break; 1086214501Srpaulo } 1087214501Srpaulo } while (class_len < 1); 1088214501Srpaulo 1089214501Srpaulo nclass[nclass_count].data = os_malloc(class_len); 1090214501Srpaulo if (nclass[nclass_count].data == NULL) 1091214501Srpaulo break; 1092214501Srpaulo 1093214501Srpaulo os_memcpy(nclass[nclass_count].data, class, class_len); 1094214501Srpaulo nclass[nclass_count].len = class_len; 1095214501Srpaulo nclass_count++; 1096214501Srpaulo } 1097214501Srpaulo 1098214501Srpaulo sm->radius_class.attr = nclass; 1099214501Srpaulo sm->radius_class.count = nclass_count; 1100214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class " 1101214501Srpaulo "attributes for " MACSTR, 1102214501Srpaulo (unsigned long) sm->radius_class.count, 1103214501Srpaulo MAC2STR(sta->addr)); 1104214501Srpaulo} 1105214501Srpaulo 1106214501Srpaulo 1107214501Srpaulo/* Update sta->identity based on User-Name attribute in Access-Accept */ 1108214501Srpaulostatic void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, 1109214501Srpaulo struct sta_info *sta, 1110214501Srpaulo struct radius_msg *msg) 1111214501Srpaulo{ 1112214501Srpaulo u8 *buf, *identity; 1113214501Srpaulo size_t len; 1114214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1115214501Srpaulo 1116214501Srpaulo if (sm == NULL) 1117214501Srpaulo return; 1118214501Srpaulo 1119214501Srpaulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, 1120214501Srpaulo NULL) < 0) 1121214501Srpaulo return; 1122214501Srpaulo 1123214501Srpaulo identity = os_malloc(len + 1); 1124214501Srpaulo if (identity == NULL) 1125214501Srpaulo return; 1126214501Srpaulo 1127214501Srpaulo os_memcpy(identity, buf, len); 1128214501Srpaulo identity[len] = '\0'; 1129214501Srpaulo 1130214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1131214501Srpaulo HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with " 1132214501Srpaulo "User-Name from Access-Accept '%s'", 1133214501Srpaulo sm->identity ? (char *) sm->identity : "N/A", 1134214501Srpaulo (char *) identity); 1135214501Srpaulo 1136214501Srpaulo os_free(sm->identity); 1137214501Srpaulo sm->identity = identity; 1138214501Srpaulo sm->identity_len = len; 1139214501Srpaulo} 1140214501Srpaulo 1141214501Srpaulo 1142214501Srpaulostruct sta_id_search { 1143214501Srpaulo u8 identifier; 1144214501Srpaulo struct eapol_state_machine *sm; 1145214501Srpaulo}; 1146214501Srpaulo 1147214501Srpaulo 1148214501Srpaulostatic int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, 1149214501Srpaulo struct sta_info *sta, 1150214501Srpaulo void *ctx) 1151214501Srpaulo{ 1152214501Srpaulo struct sta_id_search *id_search = ctx; 1153214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1154214501Srpaulo 1155214501Srpaulo if (sm && sm->radius_identifier >= 0 && 1156214501Srpaulo sm->radius_identifier == id_search->identifier) { 1157214501Srpaulo id_search->sm = sm; 1158214501Srpaulo return 1; 1159214501Srpaulo } 1160214501Srpaulo return 0; 1161214501Srpaulo} 1162214501Srpaulo 1163214501Srpaulo 1164214501Srpaulostatic struct eapol_state_machine * 1165214501Srpauloieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier) 1166214501Srpaulo{ 1167214501Srpaulo struct sta_id_search id_search; 1168214501Srpaulo id_search.identifier = identifier; 1169214501Srpaulo id_search.sm = NULL; 1170214501Srpaulo ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); 1171214501Srpaulo return id_search.sm; 1172214501Srpaulo} 1173214501Srpaulo 1174214501Srpaulo 1175214501Srpaulo/** 1176214501Srpaulo * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server 1177214501Srpaulo * @msg: RADIUS response message 1178214501Srpaulo * @req: RADIUS request message 1179214501Srpaulo * @shared_secret: RADIUS shared secret 1180214501Srpaulo * @shared_secret_len: Length of shared_secret in octets 1181214501Srpaulo * @data: Context data (struct hostapd_data *) 1182214501Srpaulo * Returns: Processing status 1183214501Srpaulo */ 1184214501Srpaulostatic RadiusRxResult 1185214501Srpauloieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 1186214501Srpaulo const u8 *shared_secret, size_t shared_secret_len, 1187214501Srpaulo void *data) 1188214501Srpaulo{ 1189214501Srpaulo struct hostapd_data *hapd = data; 1190214501Srpaulo struct sta_info *sta; 1191214501Srpaulo u32 session_timeout = 0, termination_action, acct_interim_interval; 1192214501Srpaulo int session_timeout_set, old_vlanid = 0; 1193214501Srpaulo struct eapol_state_machine *sm; 1194214501Srpaulo int override_eapReq = 0; 1195214501Srpaulo struct radius_hdr *hdr = radius_msg_get_hdr(msg); 1196214501Srpaulo 1197214501Srpaulo sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); 1198214501Srpaulo if (sm == NULL) { 1199214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching " 1200214501Srpaulo "station for this RADIUS message"); 1201214501Srpaulo return RADIUS_RX_UNKNOWN; 1202214501Srpaulo } 1203214501Srpaulo sta = sm->sta; 1204214501Srpaulo 1205214501Srpaulo /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be 1206214501Srpaulo * present when packet contains an EAP-Message attribute */ 1207214501Srpaulo if (hdr->code == RADIUS_CODE_ACCESS_REJECT && 1208214501Srpaulo radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 1209214501Srpaulo 0) < 0 && 1210214501Srpaulo radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { 1211214501Srpaulo wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without " 1212214501Srpaulo "Message-Authenticator since it does not include " 1213214501Srpaulo "EAP-Message"); 1214214501Srpaulo } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, 1215214501Srpaulo req, 1)) { 1216214501Srpaulo printf("Incoming RADIUS packet did not have correct " 1217214501Srpaulo "Message-Authenticator - dropped\n"); 1218214501Srpaulo return RADIUS_RX_INVALID_AUTHENTICATOR; 1219214501Srpaulo } 1220214501Srpaulo 1221214501Srpaulo if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 1222214501Srpaulo hdr->code != RADIUS_CODE_ACCESS_REJECT && 1223214501Srpaulo hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { 1224214501Srpaulo printf("Unknown RADIUS message code\n"); 1225214501Srpaulo return RADIUS_RX_UNKNOWN; 1226214501Srpaulo } 1227214501Srpaulo 1228214501Srpaulo sm->radius_identifier = -1; 1229214501Srpaulo wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR, 1230214501Srpaulo MAC2STR(sta->addr)); 1231214501Srpaulo 1232214501Srpaulo radius_msg_free(sm->last_recv_radius); 1233214501Srpaulo sm->last_recv_radius = msg; 1234214501Srpaulo 1235214501Srpaulo session_timeout_set = 1236214501Srpaulo !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 1237214501Srpaulo &session_timeout); 1238214501Srpaulo if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, 1239214501Srpaulo &termination_action)) 1240214501Srpaulo termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; 1241214501Srpaulo 1242214501Srpaulo if (hapd->conf->acct_interim_interval == 0 && 1243214501Srpaulo hdr->code == RADIUS_CODE_ACCESS_ACCEPT && 1244214501Srpaulo radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 1245214501Srpaulo &acct_interim_interval) == 0) { 1246214501Srpaulo if (acct_interim_interval < 60) { 1247214501Srpaulo hostapd_logger(hapd, sta->addr, 1248214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 1249214501Srpaulo HOSTAPD_LEVEL_INFO, 1250214501Srpaulo "ignored too small " 1251214501Srpaulo "Acct-Interim-Interval %d", 1252214501Srpaulo acct_interim_interval); 1253214501Srpaulo } else 1254214501Srpaulo sta->acct_interim_interval = acct_interim_interval; 1255214501Srpaulo } 1256214501Srpaulo 1257214501Srpaulo 1258214501Srpaulo switch (hdr->code) { 1259214501Srpaulo case RADIUS_CODE_ACCESS_ACCEPT: 1260214501Srpaulo if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) 1261214501Srpaulo sta->vlan_id = 0; 1262214501Srpaulo#ifndef CONFIG_NO_VLAN 1263214501Srpaulo else { 1264214501Srpaulo old_vlanid = sta->vlan_id; 1265214501Srpaulo sta->vlan_id = radius_msg_get_vlanid(msg); 1266214501Srpaulo } 1267214501Srpaulo if (sta->vlan_id > 0 && 1268214501Srpaulo hostapd_get_vlan_id_ifname(hapd->conf->vlan, 1269214501Srpaulo sta->vlan_id)) { 1270214501Srpaulo hostapd_logger(hapd, sta->addr, 1271214501Srpaulo HOSTAPD_MODULE_RADIUS, 1272214501Srpaulo HOSTAPD_LEVEL_INFO, 1273214501Srpaulo "VLAN ID %d", sta->vlan_id); 1274214501Srpaulo } else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) { 1275214501Srpaulo sta->eapol_sm->authFail = TRUE; 1276214501Srpaulo hostapd_logger(hapd, sta->addr, 1277214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 1278214501Srpaulo HOSTAPD_LEVEL_INFO, "authentication " 1279214501Srpaulo "server did not include required VLAN " 1280214501Srpaulo "ID in Access-Accept"); 1281214501Srpaulo break; 1282214501Srpaulo } 1283214501Srpaulo#endif /* CONFIG_NO_VLAN */ 1284214501Srpaulo 1285214501Srpaulo if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0) 1286214501Srpaulo break; 1287214501Srpaulo 1288214501Srpaulo /* RFC 3580, Ch. 3.17 */ 1289214501Srpaulo if (session_timeout_set && termination_action == 1290214501Srpaulo RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) { 1291214501Srpaulo sm->reAuthPeriod = session_timeout; 1292214501Srpaulo } else if (session_timeout_set) 1293214501Srpaulo ap_sta_session_timeout(hapd, sta, session_timeout); 1294214501Srpaulo 1295214501Srpaulo sm->eap_if->aaaSuccess = TRUE; 1296214501Srpaulo override_eapReq = 1; 1297214501Srpaulo ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, 1298214501Srpaulo shared_secret_len); 1299214501Srpaulo ieee802_1x_store_radius_class(hapd, sta, msg); 1300214501Srpaulo ieee802_1x_update_sta_identity(hapd, sta, msg); 1301214501Srpaulo if (sm->eap_if->eapKeyAvailable && 1302214501Srpaulo wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt, 1303214501Srpaulo session_timeout_set ? 1304214501Srpaulo (int) session_timeout : -1, sm) == 0) { 1305214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 1306214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1307214501Srpaulo "Added PMKSA cache entry"); 1308214501Srpaulo } 1309214501Srpaulo break; 1310214501Srpaulo case RADIUS_CODE_ACCESS_REJECT: 1311214501Srpaulo sm->eap_if->aaaFail = TRUE; 1312214501Srpaulo override_eapReq = 1; 1313214501Srpaulo break; 1314214501Srpaulo case RADIUS_CODE_ACCESS_CHALLENGE: 1315214501Srpaulo sm->eap_if->aaaEapReq = TRUE; 1316214501Srpaulo if (session_timeout_set) { 1317214501Srpaulo /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ 1318214501Srpaulo sm->eap_if->aaaMethodTimeout = session_timeout; 1319214501Srpaulo hostapd_logger(hapd, sm->addr, 1320214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 1321214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1322214501Srpaulo "using EAP timeout of %d seconds (from " 1323214501Srpaulo "RADIUS)", 1324214501Srpaulo sm->eap_if->aaaMethodTimeout); 1325214501Srpaulo } else { 1326214501Srpaulo /* 1327214501Srpaulo * Use dynamic retransmission behavior per EAP 1328214501Srpaulo * specification. 1329214501Srpaulo */ 1330214501Srpaulo sm->eap_if->aaaMethodTimeout = 0; 1331214501Srpaulo } 1332214501Srpaulo break; 1333214501Srpaulo } 1334214501Srpaulo 1335214501Srpaulo ieee802_1x_decapsulate_radius(hapd, sta); 1336214501Srpaulo if (override_eapReq) 1337214501Srpaulo sm->eap_if->aaaEapReq = FALSE; 1338214501Srpaulo 1339214501Srpaulo eapol_auth_step(sm); 1340214501Srpaulo 1341214501Srpaulo return RADIUS_RX_QUEUED; 1342214501Srpaulo} 1343214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1344214501Srpaulo 1345214501Srpaulo 1346214501Srpaulovoid ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) 1347214501Srpaulo{ 1348214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1349214501Srpaulo if (sm == NULL) 1350214501Srpaulo return; 1351214501Srpaulo 1352214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1353214501Srpaulo HOSTAPD_LEVEL_DEBUG, "aborting authentication"); 1354214501Srpaulo 1355214501Srpaulo#ifndef CONFIG_NO_RADIUS 1356214501Srpaulo radius_msg_free(sm->last_recv_radius); 1357214501Srpaulo sm->last_recv_radius = NULL; 1358214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1359214501Srpaulo 1360214501Srpaulo if (sm->eap_if->eapTimeout) { 1361214501Srpaulo /* 1362214501Srpaulo * Disconnect the STA since it did not reply to the last EAP 1363214501Srpaulo * request and we cannot continue EAP processing (EAP-Failure 1364214501Srpaulo * could only be sent if the EAP peer actually replied). 1365214501Srpaulo */ 1366214501Srpaulo sm->eap_if->portEnabled = FALSE; 1367214501Srpaulo ap_sta_disconnect(hapd, sta, sta->addr, 1368214501Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 1369214501Srpaulo } 1370214501Srpaulo} 1371214501Srpaulo 1372214501Srpaulo 1373214501Srpaulostatic int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) 1374214501Srpaulo{ 1375214501Srpaulo struct eapol_authenticator *eapol = hapd->eapol_auth; 1376214501Srpaulo 1377214501Srpaulo if (hapd->conf->default_wep_key_len < 1) 1378214501Srpaulo return 0; 1379214501Srpaulo 1380214501Srpaulo os_free(eapol->default_wep_key); 1381214501Srpaulo eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); 1382214501Srpaulo if (eapol->default_wep_key == NULL || 1383214501Srpaulo os_get_random(eapol->default_wep_key, 1384214501Srpaulo hapd->conf->default_wep_key_len)) { 1385214501Srpaulo printf("Could not generate random WEP key.\n"); 1386214501Srpaulo os_free(eapol->default_wep_key); 1387214501Srpaulo eapol->default_wep_key = NULL; 1388214501Srpaulo return -1; 1389214501Srpaulo } 1390214501Srpaulo 1391214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", 1392214501Srpaulo eapol->default_wep_key, 1393214501Srpaulo hapd->conf->default_wep_key_len); 1394214501Srpaulo 1395214501Srpaulo return 0; 1396214501Srpaulo} 1397214501Srpaulo 1398214501Srpaulo 1399214501Srpaulostatic int ieee802_1x_sta_key_available(struct hostapd_data *hapd, 1400214501Srpaulo struct sta_info *sta, void *ctx) 1401214501Srpaulo{ 1402214501Srpaulo if (sta->eapol_sm) { 1403214501Srpaulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1404214501Srpaulo eapol_auth_step(sta->eapol_sm); 1405214501Srpaulo } 1406214501Srpaulo return 0; 1407214501Srpaulo} 1408214501Srpaulo 1409214501Srpaulo 1410214501Srpaulostatic void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) 1411214501Srpaulo{ 1412214501Srpaulo struct hostapd_data *hapd = eloop_ctx; 1413214501Srpaulo struct eapol_authenticator *eapol = hapd->eapol_auth; 1414214501Srpaulo 1415214501Srpaulo if (eapol->default_wep_key_idx >= 3) 1416214501Srpaulo eapol->default_wep_key_idx = 1417214501Srpaulo hapd->conf->individual_wep_key_len > 0 ? 1 : 0; 1418214501Srpaulo else 1419214501Srpaulo eapol->default_wep_key_idx++; 1420214501Srpaulo 1421214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", 1422214501Srpaulo eapol->default_wep_key_idx); 1423214501Srpaulo 1424214501Srpaulo if (ieee802_1x_rekey_broadcast(hapd)) { 1425214501Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 1426214501Srpaulo HOSTAPD_LEVEL_WARNING, "failed to generate a " 1427214501Srpaulo "new broadcast key"); 1428214501Srpaulo os_free(eapol->default_wep_key); 1429214501Srpaulo eapol->default_wep_key = NULL; 1430214501Srpaulo return; 1431214501Srpaulo } 1432214501Srpaulo 1433214501Srpaulo /* TODO: Could setup key for RX here, but change default TX keyid only 1434214501Srpaulo * after new broadcast key has been sent to all stations. */ 1435214501Srpaulo if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, NULL, 1436214501Srpaulo eapol->default_wep_key_idx, 1, NULL, 0, 1437214501Srpaulo eapol->default_wep_key, 1438214501Srpaulo hapd->conf->default_wep_key_len)) { 1439214501Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 1440214501Srpaulo HOSTAPD_LEVEL_WARNING, "failed to configure a " 1441214501Srpaulo "new broadcast key"); 1442214501Srpaulo os_free(eapol->default_wep_key); 1443214501Srpaulo eapol->default_wep_key = NULL; 1444214501Srpaulo return; 1445214501Srpaulo } 1446214501Srpaulo 1447214501Srpaulo ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL); 1448214501Srpaulo 1449214501Srpaulo if (hapd->conf->wep_rekeying_period > 0) { 1450214501Srpaulo eloop_register_timeout(hapd->conf->wep_rekeying_period, 0, 1451214501Srpaulo ieee802_1x_rekey, hapd, NULL); 1452214501Srpaulo } 1453214501Srpaulo} 1454214501Srpaulo 1455214501Srpaulo 1456214501Srpaulostatic void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, 1457214501Srpaulo const u8 *data, size_t datalen) 1458214501Srpaulo{ 1459214501Srpaulo#ifdef CONFIG_WPS 1460214501Srpaulo struct sta_info *sta = sta_ctx; 1461214501Srpaulo 1462214501Srpaulo if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == 1463214501Srpaulo WLAN_STA_MAYBE_WPS) { 1464214501Srpaulo const u8 *identity; 1465214501Srpaulo size_t identity_len; 1466214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1467214501Srpaulo 1468214501Srpaulo identity = eap_get_identity(sm->eap, &identity_len); 1469214501Srpaulo if (identity && 1470214501Srpaulo ((identity_len == WSC_ID_ENROLLEE_LEN && 1471214501Srpaulo os_memcmp(identity, WSC_ID_ENROLLEE, 1472214501Srpaulo WSC_ID_ENROLLEE_LEN) == 0) || 1473214501Srpaulo (identity_len == WSC_ID_REGISTRAR_LEN && 1474214501Srpaulo os_memcmp(identity, WSC_ID_REGISTRAR, 1475214501Srpaulo WSC_ID_REGISTRAR_LEN) == 0))) { 1476214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> " 1477214501Srpaulo "WLAN_STA_WPS"); 1478214501Srpaulo sta->flags |= WLAN_STA_WPS; 1479214501Srpaulo } 1480214501Srpaulo } 1481214501Srpaulo#endif /* CONFIG_WPS */ 1482214501Srpaulo 1483214501Srpaulo ieee802_1x_send(ctx, sta_ctx, type, data, datalen); 1484214501Srpaulo} 1485214501Srpaulo 1486214501Srpaulo 1487214501Srpaulostatic void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, 1488214501Srpaulo const u8 *data, size_t datalen) 1489214501Srpaulo{ 1490214501Srpaulo#ifndef CONFIG_NO_RADIUS 1491214501Srpaulo struct hostapd_data *hapd = ctx; 1492214501Srpaulo struct sta_info *sta = sta_ctx; 1493214501Srpaulo 1494214501Srpaulo ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); 1495214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1496214501Srpaulo} 1497214501Srpaulo 1498214501Srpaulo 1499214501Srpaulostatic void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, 1500214501Srpaulo int preauth) 1501214501Srpaulo{ 1502214501Srpaulo struct hostapd_data *hapd = ctx; 1503214501Srpaulo struct sta_info *sta = sta_ctx; 1504214501Srpaulo if (preauth) 1505214501Srpaulo rsn_preauth_finished(hapd, sta, success); 1506214501Srpaulo else 1507214501Srpaulo ieee802_1x_finished(hapd, sta, success); 1508214501Srpaulo} 1509214501Srpaulo 1510214501Srpaulo 1511214501Srpaulostatic int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, 1512214501Srpaulo size_t identity_len, int phase2, 1513214501Srpaulo struct eap_user *user) 1514214501Srpaulo{ 1515214501Srpaulo struct hostapd_data *hapd = ctx; 1516214501Srpaulo const struct hostapd_eap_user *eap_user; 1517214501Srpaulo int i, count; 1518214501Srpaulo 1519214501Srpaulo eap_user = hostapd_get_eap_user(hapd->conf, identity, 1520214501Srpaulo identity_len, phase2); 1521214501Srpaulo if (eap_user == NULL) 1522214501Srpaulo return -1; 1523214501Srpaulo 1524214501Srpaulo os_memset(user, 0, sizeof(*user)); 1525214501Srpaulo user->phase2 = phase2; 1526214501Srpaulo count = EAP_USER_MAX_METHODS; 1527214501Srpaulo if (count > EAP_MAX_METHODS) 1528214501Srpaulo count = EAP_MAX_METHODS; 1529214501Srpaulo for (i = 0; i < count; i++) { 1530214501Srpaulo user->methods[i].vendor = eap_user->methods[i].vendor; 1531214501Srpaulo user->methods[i].method = eap_user->methods[i].method; 1532214501Srpaulo } 1533214501Srpaulo 1534214501Srpaulo if (eap_user->password) { 1535214501Srpaulo user->password = os_malloc(eap_user->password_len); 1536214501Srpaulo if (user->password == NULL) 1537214501Srpaulo return -1; 1538214501Srpaulo os_memcpy(user->password, eap_user->password, 1539214501Srpaulo eap_user->password_len); 1540214501Srpaulo user->password_len = eap_user->password_len; 1541214501Srpaulo } 1542214501Srpaulo user->force_version = eap_user->force_version; 1543214501Srpaulo user->ttls_auth = eap_user->ttls_auth; 1544214501Srpaulo 1545214501Srpaulo return 0; 1546214501Srpaulo} 1547214501Srpaulo 1548214501Srpaulo 1549214501Srpaulostatic int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) 1550214501Srpaulo{ 1551214501Srpaulo struct hostapd_data *hapd = ctx; 1552214501Srpaulo struct sta_info *sta; 1553214501Srpaulo sta = ap_get_sta(hapd, addr); 1554214501Srpaulo if (sta == NULL || sta->eapol_sm == NULL) 1555214501Srpaulo return 0; 1556214501Srpaulo return 1; 1557214501Srpaulo} 1558214501Srpaulo 1559214501Srpaulo 1560214501Srpaulostatic void ieee802_1x_logger(void *ctx, const u8 *addr, 1561214501Srpaulo eapol_logger_level level, const char *txt) 1562214501Srpaulo{ 1563214501Srpaulo#ifndef CONFIG_NO_HOSTAPD_LOGGER 1564214501Srpaulo struct hostapd_data *hapd = ctx; 1565214501Srpaulo int hlevel; 1566214501Srpaulo 1567214501Srpaulo switch (level) { 1568214501Srpaulo case EAPOL_LOGGER_WARNING: 1569214501Srpaulo hlevel = HOSTAPD_LEVEL_WARNING; 1570214501Srpaulo break; 1571214501Srpaulo case EAPOL_LOGGER_INFO: 1572214501Srpaulo hlevel = HOSTAPD_LEVEL_INFO; 1573214501Srpaulo break; 1574214501Srpaulo case EAPOL_LOGGER_DEBUG: 1575214501Srpaulo default: 1576214501Srpaulo hlevel = HOSTAPD_LEVEL_DEBUG; 1577214501Srpaulo break; 1578214501Srpaulo } 1579214501Srpaulo 1580214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", 1581214501Srpaulo txt); 1582214501Srpaulo#endif /* CONFIG_NO_HOSTAPD_LOGGER */ 1583214501Srpaulo} 1584214501Srpaulo 1585214501Srpaulo 1586214501Srpaulostatic void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, 1587214501Srpaulo int authorized) 1588214501Srpaulo{ 1589214501Srpaulo struct hostapd_data *hapd = ctx; 1590214501Srpaulo struct sta_info *sta = sta_ctx; 1591214501Srpaulo ieee802_1x_set_sta_authorized(hapd, sta, authorized); 1592214501Srpaulo} 1593214501Srpaulo 1594214501Srpaulo 1595214501Srpaulostatic void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) 1596214501Srpaulo{ 1597214501Srpaulo struct hostapd_data *hapd = ctx; 1598214501Srpaulo struct sta_info *sta = sta_ctx; 1599214501Srpaulo ieee802_1x_abort_auth(hapd, sta); 1600214501Srpaulo} 1601214501Srpaulo 1602214501Srpaulo 1603214501Srpaulostatic void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) 1604214501Srpaulo{ 1605214501Srpaulo struct hostapd_data *hapd = ctx; 1606214501Srpaulo struct sta_info *sta = sta_ctx; 1607214501Srpaulo ieee802_1x_tx_key(hapd, sta); 1608214501Srpaulo} 1609214501Srpaulo 1610214501Srpaulo 1611214501Srpaulostatic void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, 1612214501Srpaulo enum eapol_event type) 1613214501Srpaulo{ 1614214501Srpaulo /* struct hostapd_data *hapd = ctx; */ 1615214501Srpaulo struct sta_info *sta = sta_ctx; 1616214501Srpaulo switch (type) { 1617214501Srpaulo case EAPOL_AUTH_SM_CHANGE: 1618214501Srpaulo wpa_auth_sm_notify(sta->wpa_sm); 1619214501Srpaulo break; 1620214501Srpaulo case EAPOL_AUTH_REAUTHENTICATE: 1621214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 1622214501Srpaulo break; 1623214501Srpaulo } 1624214501Srpaulo} 1625214501Srpaulo 1626214501Srpaulo 1627214501Srpauloint ieee802_1x_init(struct hostapd_data *hapd) 1628214501Srpaulo{ 1629214501Srpaulo int i; 1630214501Srpaulo struct eapol_auth_config conf; 1631214501Srpaulo struct eapol_auth_cb cb; 1632214501Srpaulo 1633214501Srpaulo os_memset(&conf, 0, sizeof(conf)); 1634214501Srpaulo conf.ctx = hapd; 1635214501Srpaulo conf.eap_reauth_period = hapd->conf->eap_reauth_period; 1636214501Srpaulo conf.wpa = hapd->conf->wpa; 1637214501Srpaulo conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; 1638214501Srpaulo conf.eap_server = hapd->conf->eap_server; 1639214501Srpaulo conf.ssl_ctx = hapd->ssl_ctx; 1640214501Srpaulo conf.msg_ctx = hapd->msg_ctx; 1641214501Srpaulo conf.eap_sim_db_priv = hapd->eap_sim_db_priv; 1642214501Srpaulo conf.eap_req_id_text = hapd->conf->eap_req_id_text; 1643214501Srpaulo conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; 1644214501Srpaulo conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key; 1645214501Srpaulo conf.eap_fast_a_id = hapd->conf->eap_fast_a_id; 1646214501Srpaulo conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; 1647214501Srpaulo conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info; 1648214501Srpaulo conf.eap_fast_prov = hapd->conf->eap_fast_prov; 1649214501Srpaulo conf.pac_key_lifetime = hapd->conf->pac_key_lifetime; 1650214501Srpaulo conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time; 1651214501Srpaulo conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; 1652214501Srpaulo conf.tnc = hapd->conf->tnc; 1653214501Srpaulo conf.wps = hapd->wps; 1654214501Srpaulo 1655214501Srpaulo os_memset(&cb, 0, sizeof(cb)); 1656214501Srpaulo cb.eapol_send = ieee802_1x_eapol_send; 1657214501Srpaulo cb.aaa_send = ieee802_1x_aaa_send; 1658214501Srpaulo cb.finished = _ieee802_1x_finished; 1659214501Srpaulo cb.get_eap_user = ieee802_1x_get_eap_user; 1660214501Srpaulo cb.sta_entry_alive = ieee802_1x_sta_entry_alive; 1661214501Srpaulo cb.logger = ieee802_1x_logger; 1662214501Srpaulo cb.set_port_authorized = ieee802_1x_set_port_authorized; 1663214501Srpaulo cb.abort_auth = _ieee802_1x_abort_auth; 1664214501Srpaulo cb.tx_key = _ieee802_1x_tx_key; 1665214501Srpaulo cb.eapol_event = ieee802_1x_eapol_event; 1666214501Srpaulo 1667214501Srpaulo hapd->eapol_auth = eapol_auth_init(&conf, &cb); 1668214501Srpaulo if (hapd->eapol_auth == NULL) 1669214501Srpaulo return -1; 1670214501Srpaulo 1671214501Srpaulo if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && 1672214501Srpaulo hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) 1673214501Srpaulo return -1; 1674214501Srpaulo 1675214501Srpaulo#ifndef CONFIG_NO_RADIUS 1676214501Srpaulo if (radius_client_register(hapd->radius, RADIUS_AUTH, 1677214501Srpaulo ieee802_1x_receive_auth, hapd)) 1678214501Srpaulo return -1; 1679214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1680214501Srpaulo 1681214501Srpaulo if (hapd->conf->default_wep_key_len) { 1682214501Srpaulo for (i = 0; i < 4; i++) 1683214501Srpaulo hapd->drv.set_key(hapd->conf->iface, hapd, 1684214501Srpaulo WPA_ALG_NONE, NULL, i, 0, NULL, 0, 1685214501Srpaulo NULL, 0); 1686214501Srpaulo 1687214501Srpaulo ieee802_1x_rekey(hapd, NULL); 1688214501Srpaulo 1689214501Srpaulo if (hapd->eapol_auth->default_wep_key == NULL) 1690214501Srpaulo return -1; 1691214501Srpaulo } 1692214501Srpaulo 1693214501Srpaulo return 0; 1694214501Srpaulo} 1695214501Srpaulo 1696214501Srpaulo 1697214501Srpaulovoid ieee802_1x_deinit(struct hostapd_data *hapd) 1698214501Srpaulo{ 1699214501Srpaulo eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); 1700214501Srpaulo 1701214501Srpaulo if (hapd->driver != NULL && 1702214501Srpaulo (hapd->conf->ieee802_1x || hapd->conf->wpa)) 1703214501Srpaulo hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 0); 1704214501Srpaulo 1705214501Srpaulo eapol_auth_deinit(hapd->eapol_auth); 1706214501Srpaulo hapd->eapol_auth = NULL; 1707214501Srpaulo} 1708214501Srpaulo 1709214501Srpaulo 1710214501Srpauloint ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 1711214501Srpaulo const u8 *buf, size_t len, int ack) 1712214501Srpaulo{ 1713214501Srpaulo struct ieee80211_hdr *hdr; 1714214501Srpaulo struct ieee802_1x_hdr *xhdr; 1715214501Srpaulo struct ieee802_1x_eapol_key *key; 1716214501Srpaulo u8 *pos; 1717214501Srpaulo const unsigned char rfc1042_hdr[ETH_ALEN] = 1718214501Srpaulo { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 1719214501Srpaulo 1720214501Srpaulo if (sta == NULL) 1721214501Srpaulo return -1; 1722214501Srpaulo if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr)) 1723214501Srpaulo return 0; 1724214501Srpaulo 1725214501Srpaulo hdr = (struct ieee80211_hdr *) buf; 1726214501Srpaulo pos = (u8 *) (hdr + 1); 1727214501Srpaulo if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) 1728214501Srpaulo return 0; 1729214501Srpaulo pos += sizeof(rfc1042_hdr); 1730214501Srpaulo if (WPA_GET_BE16(pos) != ETH_P_PAE) 1731214501Srpaulo return 0; 1732214501Srpaulo pos += 2; 1733214501Srpaulo 1734214501Srpaulo xhdr = (struct ieee802_1x_hdr *) pos; 1735214501Srpaulo pos += sizeof(*xhdr); 1736214501Srpaulo 1737214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " 1738214501Srpaulo "type=%d length=%d - ack=%d", 1739214501Srpaulo MAC2STR(sta->addr), xhdr->version, xhdr->type, 1740214501Srpaulo be_to_host16(xhdr->length), ack); 1741214501Srpaulo 1742214501Srpaulo /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant 1743214501Srpaulo * or Authenticator state machines, but EAPOL-Key packets are not 1744214501Srpaulo * retransmitted in case of failure. Try to re-sent failed EAPOL-Key 1745214501Srpaulo * packets couple of times because otherwise STA keys become 1746214501Srpaulo * unsynchronized with AP. */ 1747214501Srpaulo if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack && 1748214501Srpaulo pos + sizeof(*key) <= buf + len) { 1749214501Srpaulo key = (struct ieee802_1x_eapol_key *) pos; 1750214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1751214501Srpaulo HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " 1752214501Srpaulo "frame (%scast index=%d)", 1753214501Srpaulo key->key_index & BIT(7) ? "uni" : "broad", 1754214501Srpaulo key->key_index & ~BIT(7)); 1755214501Srpaulo /* TODO: re-send EAPOL-Key couple of times (with short delay 1756214501Srpaulo * between them?). If all attempt fail, report error and 1757214501Srpaulo * deauthenticate STA so that it will get new keys when 1758214501Srpaulo * authenticating again (e.g., after returning in range). 1759214501Srpaulo * Separate limit/transmit state needed both for unicast and 1760214501Srpaulo * broadcast keys(?) */ 1761214501Srpaulo } 1762214501Srpaulo /* TODO: could move unicast key configuration from ieee802_1x_tx_key() 1763214501Srpaulo * to here and change the key only if the EAPOL-Key packet was Acked. 1764214501Srpaulo */ 1765214501Srpaulo 1766214501Srpaulo return 1; 1767214501Srpaulo} 1768214501Srpaulo 1769214501Srpaulo 1770214501Srpaulou8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len) 1771214501Srpaulo{ 1772214501Srpaulo if (sm == NULL || sm->identity == NULL) 1773214501Srpaulo return NULL; 1774214501Srpaulo 1775214501Srpaulo *len = sm->identity_len; 1776214501Srpaulo return sm->identity; 1777214501Srpaulo} 1778214501Srpaulo 1779214501Srpaulo 1780214501Srpaulou8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, 1781214501Srpaulo int idx) 1782214501Srpaulo{ 1783214501Srpaulo if (sm == NULL || sm->radius_class.attr == NULL || 1784214501Srpaulo idx >= (int) sm->radius_class.count) 1785214501Srpaulo return NULL; 1786214501Srpaulo 1787214501Srpaulo *len = sm->radius_class.attr[idx].len; 1788214501Srpaulo return sm->radius_class.attr[idx].data; 1789214501Srpaulo} 1790214501Srpaulo 1791214501Srpaulo 1792214501Srpauloconst u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) 1793214501Srpaulo{ 1794214501Srpaulo if (sm == NULL) 1795214501Srpaulo return NULL; 1796214501Srpaulo 1797214501Srpaulo *len = sm->eap_if->eapKeyDataLen; 1798214501Srpaulo return sm->eap_if->eapKeyData; 1799214501Srpaulo} 1800214501Srpaulo 1801214501Srpaulo 1802214501Srpaulovoid ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, 1803214501Srpaulo int enabled) 1804214501Srpaulo{ 1805214501Srpaulo if (sm == NULL) 1806214501Srpaulo return; 1807214501Srpaulo sm->eap_if->portEnabled = enabled ? TRUE : FALSE; 1808214501Srpaulo eapol_auth_step(sm); 1809214501Srpaulo} 1810214501Srpaulo 1811214501Srpaulo 1812214501Srpaulovoid ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, 1813214501Srpaulo int valid) 1814214501Srpaulo{ 1815214501Srpaulo if (sm == NULL) 1816214501Srpaulo return; 1817214501Srpaulo sm->portValid = valid ? TRUE : FALSE; 1818214501Srpaulo eapol_auth_step(sm); 1819214501Srpaulo} 1820214501Srpaulo 1821214501Srpaulo 1822214501Srpaulovoid ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth) 1823214501Srpaulo{ 1824214501Srpaulo if (sm == NULL) 1825214501Srpaulo return; 1826214501Srpaulo if (pre_auth) 1827214501Srpaulo sm->flags |= EAPOL_SM_PREAUTH; 1828214501Srpaulo else 1829214501Srpaulo sm->flags &= ~EAPOL_SM_PREAUTH; 1830214501Srpaulo} 1831214501Srpaulo 1832214501Srpaulo 1833214501Srpaulostatic const char * bool_txt(Boolean bool) 1834214501Srpaulo{ 1835214501Srpaulo return bool ? "TRUE" : "FALSE"; 1836214501Srpaulo} 1837214501Srpaulo 1838214501Srpaulo 1839214501Srpauloint ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 1840214501Srpaulo{ 1841214501Srpaulo /* TODO */ 1842214501Srpaulo return 0; 1843214501Srpaulo} 1844214501Srpaulo 1845214501Srpaulo 1846214501Srpauloint ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 1847214501Srpaulo char *buf, size_t buflen) 1848214501Srpaulo{ 1849214501Srpaulo int len = 0, ret; 1850214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1851214501Srpaulo 1852214501Srpaulo if (sm == NULL) 1853214501Srpaulo return 0; 1854214501Srpaulo 1855214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 1856214501Srpaulo "dot1xPaePortNumber=%d\n" 1857214501Srpaulo "dot1xPaePortProtocolVersion=%d\n" 1858214501Srpaulo "dot1xPaePortCapabilities=1\n" 1859214501Srpaulo "dot1xPaePortInitialize=%d\n" 1860214501Srpaulo "dot1xPaePortReauthenticate=FALSE\n", 1861214501Srpaulo sta->aid, 1862214501Srpaulo EAPOL_VERSION, 1863214501Srpaulo sm->initialize); 1864214501Srpaulo if (ret < 0 || (size_t) ret >= buflen - len) 1865214501Srpaulo return len; 1866214501Srpaulo len += ret; 1867214501Srpaulo 1868214501Srpaulo /* dot1xAuthConfigTable */ 1869214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 1870214501Srpaulo "dot1xAuthPaeState=%d\n" 1871214501Srpaulo "dot1xAuthBackendAuthState=%d\n" 1872214501Srpaulo "dot1xAuthAdminControlledDirections=%d\n" 1873214501Srpaulo "dot1xAuthOperControlledDirections=%d\n" 1874214501Srpaulo "dot1xAuthAuthControlledPortStatus=%d\n" 1875214501Srpaulo "dot1xAuthAuthControlledPortControl=%d\n" 1876214501Srpaulo "dot1xAuthQuietPeriod=%u\n" 1877214501Srpaulo "dot1xAuthServerTimeout=%u\n" 1878214501Srpaulo "dot1xAuthReAuthPeriod=%u\n" 1879214501Srpaulo "dot1xAuthReAuthEnabled=%s\n" 1880214501Srpaulo "dot1xAuthKeyTxEnabled=%s\n", 1881214501Srpaulo sm->auth_pae_state + 1, 1882214501Srpaulo sm->be_auth_state + 1, 1883214501Srpaulo sm->adminControlledDirections, 1884214501Srpaulo sm->operControlledDirections, 1885214501Srpaulo sm->authPortStatus, 1886214501Srpaulo sm->portControl, 1887214501Srpaulo sm->quietPeriod, 1888214501Srpaulo sm->serverTimeout, 1889214501Srpaulo sm->reAuthPeriod, 1890214501Srpaulo bool_txt(sm->reAuthEnabled), 1891214501Srpaulo bool_txt(sm->keyTxEnabled)); 1892214501Srpaulo if (ret < 0 || (size_t) ret >= buflen - len) 1893214501Srpaulo return len; 1894214501Srpaulo len += ret; 1895214501Srpaulo 1896214501Srpaulo /* dot1xAuthStatsTable */ 1897214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 1898214501Srpaulo "dot1xAuthEapolFramesRx=%u\n" 1899214501Srpaulo "dot1xAuthEapolFramesTx=%u\n" 1900214501Srpaulo "dot1xAuthEapolStartFramesRx=%u\n" 1901214501Srpaulo "dot1xAuthEapolLogoffFramesRx=%u\n" 1902214501Srpaulo "dot1xAuthEapolRespIdFramesRx=%u\n" 1903214501Srpaulo "dot1xAuthEapolRespFramesRx=%u\n" 1904214501Srpaulo "dot1xAuthEapolReqIdFramesTx=%u\n" 1905214501Srpaulo "dot1xAuthEapolReqFramesTx=%u\n" 1906214501Srpaulo "dot1xAuthInvalidEapolFramesRx=%u\n" 1907214501Srpaulo "dot1xAuthEapLengthErrorFramesRx=%u\n" 1908214501Srpaulo "dot1xAuthLastEapolFrameVersion=%u\n" 1909214501Srpaulo "dot1xAuthLastEapolFrameSource=" MACSTR "\n", 1910214501Srpaulo sm->dot1xAuthEapolFramesRx, 1911214501Srpaulo sm->dot1xAuthEapolFramesTx, 1912214501Srpaulo sm->dot1xAuthEapolStartFramesRx, 1913214501Srpaulo sm->dot1xAuthEapolLogoffFramesRx, 1914214501Srpaulo sm->dot1xAuthEapolRespIdFramesRx, 1915214501Srpaulo sm->dot1xAuthEapolRespFramesRx, 1916214501Srpaulo sm->dot1xAuthEapolReqIdFramesTx, 1917214501Srpaulo sm->dot1xAuthEapolReqFramesTx, 1918214501Srpaulo sm->dot1xAuthInvalidEapolFramesRx, 1919214501Srpaulo sm->dot1xAuthEapLengthErrorFramesRx, 1920214501Srpaulo sm->dot1xAuthLastEapolFrameVersion, 1921214501Srpaulo MAC2STR(sm->addr)); 1922214501Srpaulo if (ret < 0 || (size_t) ret >= buflen - len) 1923214501Srpaulo return len; 1924214501Srpaulo len += ret; 1925214501Srpaulo 1926214501Srpaulo /* dot1xAuthDiagTable */ 1927214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 1928214501Srpaulo "dot1xAuthEntersConnecting=%u\n" 1929214501Srpaulo "dot1xAuthEapLogoffsWhileConnecting=%u\n" 1930214501Srpaulo "dot1xAuthEntersAuthenticating=%u\n" 1931214501Srpaulo "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n" 1932214501Srpaulo "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n" 1933214501Srpaulo "dot1xAuthAuthFailWhileAuthenticating=%u\n" 1934214501Srpaulo "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n" 1935214501Srpaulo "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n" 1936214501Srpaulo "dot1xAuthAuthReauthsWhileAuthenticated=%u\n" 1937214501Srpaulo "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n" 1938214501Srpaulo "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n" 1939214501Srpaulo "dot1xAuthBackendResponses=%u\n" 1940214501Srpaulo "dot1xAuthBackendAccessChallenges=%u\n" 1941214501Srpaulo "dot1xAuthBackendOtherRequestsToSupplicant=%u\n" 1942214501Srpaulo "dot1xAuthBackendAuthSuccesses=%u\n" 1943214501Srpaulo "dot1xAuthBackendAuthFails=%u\n", 1944214501Srpaulo sm->authEntersConnecting, 1945214501Srpaulo sm->authEapLogoffsWhileConnecting, 1946214501Srpaulo sm->authEntersAuthenticating, 1947214501Srpaulo sm->authAuthSuccessesWhileAuthenticating, 1948214501Srpaulo sm->authAuthTimeoutsWhileAuthenticating, 1949214501Srpaulo sm->authAuthFailWhileAuthenticating, 1950214501Srpaulo sm->authAuthEapStartsWhileAuthenticating, 1951214501Srpaulo sm->authAuthEapLogoffWhileAuthenticating, 1952214501Srpaulo sm->authAuthReauthsWhileAuthenticated, 1953214501Srpaulo sm->authAuthEapStartsWhileAuthenticated, 1954214501Srpaulo sm->authAuthEapLogoffWhileAuthenticated, 1955214501Srpaulo sm->backendResponses, 1956214501Srpaulo sm->backendAccessChallenges, 1957214501Srpaulo sm->backendOtherRequestsToSupplicant, 1958214501Srpaulo sm->backendAuthSuccesses, 1959214501Srpaulo sm->backendAuthFails); 1960214501Srpaulo if (ret < 0 || (size_t) ret >= buflen - len) 1961214501Srpaulo return len; 1962214501Srpaulo len += ret; 1963214501Srpaulo 1964214501Srpaulo /* dot1xAuthSessionStatsTable */ 1965214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 1966214501Srpaulo /* TODO: dot1xAuthSessionOctetsRx */ 1967214501Srpaulo /* TODO: dot1xAuthSessionOctetsTx */ 1968214501Srpaulo /* TODO: dot1xAuthSessionFramesRx */ 1969214501Srpaulo /* TODO: dot1xAuthSessionFramesTx */ 1970214501Srpaulo "dot1xAuthSessionId=%08X-%08X\n" 1971214501Srpaulo "dot1xAuthSessionAuthenticMethod=%d\n" 1972214501Srpaulo "dot1xAuthSessionTime=%u\n" 1973214501Srpaulo "dot1xAuthSessionTerminateCause=999\n" 1974214501Srpaulo "dot1xAuthSessionUserName=%s\n", 1975214501Srpaulo sta->acct_session_id_hi, sta->acct_session_id_lo, 1976214501Srpaulo (wpa_key_mgmt_wpa_ieee8021x( 1977214501Srpaulo wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 1978214501Srpaulo 1 : 2, 1979214501Srpaulo (unsigned int) (time(NULL) - 1980214501Srpaulo sta->acct_session_start), 1981214501Srpaulo sm->identity); 1982214501Srpaulo if (ret < 0 || (size_t) ret >= buflen - len) 1983214501Srpaulo return len; 1984214501Srpaulo len += ret; 1985214501Srpaulo 1986214501Srpaulo return len; 1987214501Srpaulo} 1988214501Srpaulo 1989214501Srpaulo 1990214501Srpaulostatic void ieee802_1x_finished(struct hostapd_data *hapd, 1991214501Srpaulo struct sta_info *sta, int success) 1992214501Srpaulo{ 1993214501Srpaulo const u8 *key; 1994214501Srpaulo size_t len; 1995214501Srpaulo /* TODO: get PMKLifetime from WPA parameters */ 1996214501Srpaulo static const int dot11RSNAConfigPMKLifetime = 43200; 1997214501Srpaulo 1998214501Srpaulo key = ieee802_1x_get_key(sta->eapol_sm, &len); 1999214501Srpaulo if (success && key && len >= PMK_LEN && 2000214501Srpaulo wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime, 2001214501Srpaulo sta->eapol_sm) == 0) { 2002214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 2003214501Srpaulo HOSTAPD_LEVEL_DEBUG, 2004214501Srpaulo "Added PMKSA cache entry (IEEE 802.1X)"); 2005214501Srpaulo } 2006214501Srpaulo 2007214501Srpaulo#ifdef CONFIG_WPS 2008214501Srpaulo if (!success && (sta->flags & WLAN_STA_WPS)) { 2009214501Srpaulo /* 2010214501Srpaulo * Many devices require deauthentication after WPS provisioning 2011214501Srpaulo * and some may not be be able to do that themselves, so 2012214501Srpaulo * disconnect the client here. 2013214501Srpaulo */ 2014214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: Force disconnection after " 2015214501Srpaulo "EAP-Failure"); 2016214501Srpaulo /* Add a small sleep to increase likelihood of previously 2017214501Srpaulo * requested EAP-Failure TX getting out before this should the 2018214501Srpaulo * driver reorder operations. 2019214501Srpaulo */ 2020214501Srpaulo os_sleep(0, 10000); 2021214501Srpaulo ap_sta_disconnect(hapd, sta, sta->addr, 2022214501Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 2023214501Srpaulo } 2024214501Srpaulo#endif /* CONFIG_WPS */ 2025214501Srpaulo} 2026