diff options
Diffstat (limited to 'contrib/wpa/src/ap/ieee802_1x.c')
-rw-r--r-- | contrib/wpa/src/ap/ieee802_1x.c | 557 |
1 files changed, 387 insertions, 170 deletions
diff --git a/contrib/wpa/src/ap/ieee802_1x.c b/contrib/wpa/src/ap/ieee802_1x.c index eb160f8..d9c21a8 100644 --- a/contrib/wpa/src/ap/ieee802_1x.c +++ b/contrib/wpa/src/ap/ieee802_1x.c @@ -1,15 +1,9 @@ /* * hostapd / IEEE 802.1X-2004 Authenticator - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" @@ -18,14 +12,15 @@ #include "utils/eloop.h" #include "crypto/md5.h" #include "crypto/crypto.h" +#include "crypto/random.h" #include "common/ieee802_11_defs.h" -#include "common/wpa_ctrl.h" #include "radius/radius.h" #include "radius/radius_client.h" #include "eap_server/eap.h" #include "eap_common/eap_wsc_common.h" #include "eapol_auth/eapol_auth_sm.h" #include "eapol_auth/eapol_auth_sm_i.h" +#include "p2p/p2p.h" #include "hostapd.h" #include "accounting.h" #include "sta_info.h" @@ -33,6 +28,7 @@ #include "preauth_auth.h" #include "pmksa_cache_auth.h" #include "ap_config.h" +#include "ap_drv_ops.h" #include "ieee802_1x.h" @@ -70,7 +66,9 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, if (sta->flags & WLAN_STA_PREAUTH) { rsn_preauth_send(hapd, sta, buf, len); } else { - hapd->drv.send_eapol(hapd, sta->addr, buf, len, encrypt); + hostapd_drv_hapd_send_eapol( + hapd, sta->addr, buf, len, + encrypt, hostapd_sta_flags_to_drv(sta->flags)); } os_free(buf); @@ -86,21 +84,13 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, return; if (authorized) { - if (!(sta->flags & WLAN_STA_AUTHORIZED)) - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); - sta->flags |= WLAN_STA_AUTHORIZED; - res = hapd->drv.set_authorized(hapd, sta, 1); + ap_sta_set_authorized(hapd, sta, 1); + res = hostapd_set_authorized(hapd, sta, 1); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "authorizing port"); } else { - if ((sta->flags & (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC)) == - (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC)) - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); - sta->flags &= ~WLAN_STA_AUTHORIZED; - res = hapd->drv.set_authorized(hapd, sta, 0); + ap_sta_set_authorized(hapd, sta, 0); + res = hostapd_set_authorized(hapd, sta, 0); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); } @@ -110,8 +100,10 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, "driver (errno=%d).\n", MAC2STR(sta->addr), errno); } - if (authorized) + if (authorized) { + os_get_time(&sta->connected_time); accounting_sta_start(hapd, sta); + } } @@ -137,10 +129,10 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, hdr = (struct ieee802_1x_hdr *) buf; key = (struct ieee802_1x_eapol_key *) (hdr + 1); key->type = EAPOL_KEY_TYPE_RC4; - key->key_length = htons(key_len); + WPA_PUT_BE16(key->key_length, key_len); wpa_get_ntp_timestamp(key->replay_counter); - if (os_get_random(key->key_iv, sizeof(key->key_iv))) { + if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) { wpa_printf(MSG_ERROR, "Could not get random numbers"); os_free(buf); return; @@ -215,7 +207,7 @@ ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname) if (!key->key[key->idx]) key->key[key->idx] = os_malloc(key->default_len); if (key->key[key->idx] == NULL || - os_get_random(key->key[key->idx], key->default_len)) { + random_get_bytes(key->key[key->idx], key->default_len)) { printf("Could not generate random WEP key (dynamic VLAN).\n"); os_free(key->key[key->idx]); key->key[key->idx] = NULL; @@ -229,11 +221,13 @@ ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname) wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)", key->key[key->idx], key->len[key->idx]); - if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL, key->idx, 1, - NULL, 0, key->key[key->idx], key->len[key->idx])) + if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP, + broadcast_ether_addr, key->idx, 1, + NULL, 0, key->key[key->idx], + key->len[key->idx])) printf("Could not set dynamic VLAN WEP encryption key.\n"); - hapd->drv.set_drv_ieee8021x(hapd, ifname, 1); + hostapd_set_drv_ieee8021x(hapd, ifname, 1); return key; } @@ -330,7 +324,8 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) u8 *ikey; ikey = os_malloc(hapd->conf->individual_wep_key_len); if (ikey == NULL || - os_get_random(ikey, hapd->conf->individual_wep_key_len)) { + random_get_bytes(ikey, hapd->conf->individual_wep_key_len)) + { wpa_printf(MSG_ERROR, "Could not generate random " "individual WEP key."); os_free(ikey); @@ -345,9 +340,9 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) /* TODO: set encryption in TX callback, i.e., only after STA * has ACKed EAPOL-Key frame */ - if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, - sta->addr, 0, 1, NULL, 0, ikey, - hapd->conf->individual_wep_key_len)) { + if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, + sta->addr, 0, 1, NULL, 0, ikey, + hapd->conf->individual_wep_key_len)) { wpa_printf(MSG_ERROR, "Could not set individual WEP " "encryption."); } @@ -360,6 +355,8 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) const char *radius_mode_txt(struct hostapd_data *hapd) { switch (hapd->iface->conf->hw_mode) { + case HOSTAPD_MODE_IEEE80211AD: + return "802.11ad"; case HOSTAPD_MODE_IEEE80211A: return "802.11a"; case HOSTAPD_MODE_IEEE80211G: @@ -417,12 +414,142 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd, } +static int add_common_radius_sta_attr(struct hostapd_data *hapd, + struct hostapd_radius_attr *req_attr, + struct sta_info *sta, + struct radius_msg *msg) +{ + char buf[128]; + + if (!hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_NAS_PORT) && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { + wpa_printf(MSG_ERROR, "Could not add NAS-Port"); + return -1; + } + + os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, + MAC2STR(sta->addr)); + buf[sizeof(buf) - 1] = '\0'; + if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, + (u8 *) buf, os_strlen(buf))) { + wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id"); + return -1; + } + + if (sta->flags & WLAN_STA_PREAUTH) { + os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", + sizeof(buf)); + } else { + os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", + radius_sta_rate(hapd, sta) / 2, + (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", + radius_mode_txt(hapd)); + buf[sizeof(buf) - 1] = '\0'; + } + if (!hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_CONNECT_INFO) && + !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, + (u8 *) buf, os_strlen(buf))) { + wpa_printf(MSG_ERROR, "Could not add Connect-Info"); + return -1; + } + + if (sta->acct_session_id_hi || sta->acct_session_id_lo) { + os_snprintf(buf, sizeof(buf), "%08X-%08X", + sta->acct_session_id_hi, sta->acct_session_id_lo); + if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, + (u8 *) buf, os_strlen(buf))) { + wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id"); + return -1; + } + } + + return 0; +} + + +int add_common_radius_attr(struct hostapd_data *hapd, + struct hostapd_radius_attr *req_attr, + struct sta_info *sta, + struct radius_msg *msg) +{ + char buf[128]; + struct hostapd_radius_attr *attr; + + if (!hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_NAS_IP_ADDRESS) && + hapd->conf->own_ip_addr.af == AF_INET && + !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, + (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { + wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address"); + return -1; + } + +#ifdef CONFIG_IPV6 + if (!hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_NAS_IPV6_ADDRESS) && + hapd->conf->own_ip_addr.af == AF_INET6 && + !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, + (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { + wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address"); + return -1; + } +#endif /* CONFIG_IPV6 */ + + if (!hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_NAS_IDENTIFIER) && + hapd->conf->nas_identifier && + !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, + (u8 *) hapd->conf->nas_identifier, + os_strlen(hapd->conf->nas_identifier))) { + wpa_printf(MSG_ERROR, "Could not add NAS-Identifier"); + return -1; + } + + os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", + MAC2STR(hapd->own_addr), + wpa_ssid_txt(hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len)); + buf[sizeof(buf) - 1] = '\0'; + if (!hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_CALLED_STATION_ID) && + !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, + (u8 *) buf, os_strlen(buf))) { + wpa_printf(MSG_ERROR, "Could not add Called-Station-Id"); + return -1; + } + + if (!hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_NAS_PORT_TYPE) && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, + RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { + wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type"); + return -1; + } + + if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0) + return -1; + + for (attr = req_attr; attr; attr = attr->next) { + if (!radius_msg_add_attr(msg, attr->type, + wpabuf_head(attr->val), + wpabuf_len(attr->val))) { + wpa_printf(MSG_ERROR, "Could not add RADIUS " + "attribute"); + return -1; + } + } + + return 0; +} + + static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, struct sta_info *sta, const u8 *eap, size_t len) { struct radius_msg *msg; - char buf[128]; struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) @@ -450,83 +577,20 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, goto fail; } - if (hapd->conf->own_ip_addr.af == AF_INET && - !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, - (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { - printf("Could not add NAS-IP-Address\n"); - goto fail; - } - -#ifdef CONFIG_IPV6 - if (hapd->conf->own_ip_addr.af == AF_INET6 && - !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, - (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { - printf("Could not add NAS-IPv6-Address\n"); - goto fail; - } -#endif /* CONFIG_IPV6 */ - - if (hapd->conf->nas_identifier && - !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, - (u8 *) hapd->conf->nas_identifier, - os_strlen(hapd->conf->nas_identifier))) { - printf("Could not add NAS-Identifier\n"); - goto fail; - } - - if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { - printf("Could not add NAS-Port\n"); - goto fail; - } - - os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", - MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid); - buf[sizeof(buf) - 1] = '\0'; - if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, - (u8 *) buf, os_strlen(buf))) { - printf("Could not add Called-Station-Id\n"); - goto fail; - } - - os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, - MAC2STR(sta->addr)); - buf[sizeof(buf) - 1] = '\0'; - if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, - (u8 *) buf, os_strlen(buf))) { - printf("Could not add Calling-Station-Id\n"); + if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta, + msg) < 0) goto fail; - } /* TODO: should probably check MTU from driver config; 2304 is max for * IEEE 802.11, but use 1400 to avoid problems with too large packets */ - if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { + if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr, + RADIUS_ATTR_FRAMED_MTU) && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { printf("Could not add Framed-MTU\n"); goto fail; } - if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, - RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { - printf("Could not add NAS-Port-Type\n"); - goto fail; - } - - if (sta->flags & WLAN_STA_PREAUTH) { - os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", - sizeof(buf)); - } else { - os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", - radius_sta_rate(hapd, sta) / 2, - (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", - radius_mode_txt(hapd)); - buf[sizeof(buf) - 1] = '\0'; - } - if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, - (u8 *) buf, os_strlen(buf))) { - printf("Could not add Connect-Info\n"); - goto fail; - } - if (eap && !radius_msg_add_eap(msg, eap, len)) { printf("Could not add EAP-Message\n"); goto fail; @@ -549,7 +613,28 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, } } - radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr); + if (hapd->conf->radius_request_cui) { + const u8 *cui; + size_t cui_len; + /* Add previously learned CUI or nul CUI to request CUI */ + if (sm->radius_cui) { + cui = wpabuf_head(sm->radius_cui); + cui_len = wpabuf_len(sm->radius_cui); + } else { + cui = (const u8 *) "\0"; + cui_len = 1; + } + if (!radius_msg_add_attr(msg, + RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, + cui, cui_len)) { + wpa_printf(MSG_ERROR, "Could not add CUI"); + goto fail; + } + } + + if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0) + goto fail; + return; fail: @@ -652,7 +737,8 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) flags |= EAPOL_SM_FROM_PMKSA_CACHE; } return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, - sta->wps_ie, sta); + sta->wps_ie, sta->p2p_ie, sta, + sta->identity, sta->radius_cui); } @@ -673,6 +759,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, struct ieee802_1x_eapol_key *key; u16 datalen; struct rsn_pmksa_cache_entry *pmksa; + int key_mgmt; if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->wps_state) @@ -681,9 +768,10 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, (unsigned long) len, MAC2STR(sa)); sta = ap_get_sta(hapd, sa); - if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { + if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && + !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " - "associated STA"); + "associated/Pre-authenticating STA"); return; } @@ -724,10 +812,19 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, return; } - if ((!hapd->conf->ieee802_1x && - !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) || - wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm))) + if (!hapd->conf->ieee802_1x && + !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { + wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " + "802.1X not enabled and WPS not used"); + return; + } + + key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); + if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) { + wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " + "STA is using PSK"); return; + } if (!sta->eapol_sm) { sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); @@ -735,14 +832,24 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, return; #ifdef CONFIG_WPS - if (!hapd->conf->ieee802_1x && - ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == - WLAN_STA_MAYBE_WPS)) { - /* - * Delay EAPOL frame transmission until a possible WPS - * STA initiates the handshake with EAPOL-Start. - */ - sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; + if (!hapd->conf->ieee802_1x) { + u32 wflags = sta->flags & (WLAN_STA_WPS | + WLAN_STA_WPS2 | + WLAN_STA_MAYBE_WPS); + if (wflags == WLAN_STA_MAYBE_WPS || + wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { + /* + * Delay EAPOL frame transmission until a + * possible WPS STA initiates the handshake + * with EAPOL-Start. Only allow the wait to be + * skipped if the STA is known to support WPS + * 2.0. + */ + wpa_printf(MSG_DEBUG, "WPS: Do not start " + "EAPOL until EAPOL-Start is " + "received"); + sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; + } } #endif /* CONFIG_WPS */ @@ -776,6 +883,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, } sta->eapol_sm->eapolStart = TRUE; sta->eapol_sm->dot1xAuthEapolStartFramesRx++; + eap_server_clear_identity(sta->eapol_sm->eap); wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); break; @@ -788,11 +896,12 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, accounting_sta_stop(hapd, sta); sta->eapol_sm->eapolLogoff = TRUE; sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; + eap_server_clear_identity(sta->eapol_sm->eap); break; case IEEE802_1X_TYPE_EAPOL_KEY: wpa_printf(MSG_DEBUG, " EAPOL-Key"); - if (!(sta->flags & WLAN_STA_AUTHORIZED)) { + if (!ap_sta_is_authorized(sta)) { wpa_printf(MSG_DEBUG, " Dropped key data from " "unauthorized Supplicant"); break; @@ -827,6 +936,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) struct rsn_pmksa_cache_entry *pmksa; int reassoc = 1; int force_1x = 0; + int key_mgmt; #ifdef CONFIG_WPS if (hapd->conf->wps_state && hapd->conf->wpa && @@ -840,9 +950,27 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) } #endif /* CONFIG_WPS */ - if ((!force_1x && !hapd->conf->ieee802_1x) || - wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm))) + if (!force_1x && !hapd->conf->ieee802_1x) { + wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - " + "802.1X not enabled or forced for WPS"); + /* + * Clear any possible EAPOL authenticator state to support + * reassociation change from WPS to PSK. + */ + ieee802_1x_free_station(sta); return; + } + + key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); + if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) { + wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK"); + /* + * Clear any possible EAPOL authenticator state to support + * reassociation change from WPA-EAP to PSK. + */ + ieee802_1x_free_station(sta); + return; + } if (sta->eapol_sm == NULL) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, @@ -860,17 +988,40 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) #ifdef CONFIG_WPS sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; - if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) { + if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) { /* - * Delay EAPOL frame transmission until a possible WPS - * initiates the handshake with EAPOL-Start. + * Delay EAPOL frame transmission until a possible WPS STA + * initiates the handshake with EAPOL-Start. Only allow the + * wait to be skipped if the STA is known to support WPS 2.0. */ + wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until " + "EAPOL-Start is received"); sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; } #endif /* CONFIG_WPS */ sta->eapol_sm->eap_if->portEnabled = TRUE; +#ifdef CONFIG_IEEE80211R + if (sta->auth_alg == WLAN_AUTH_FT) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, + HOSTAPD_LEVEL_DEBUG, + "PMK from FT - skip IEEE 802.1X/EAP"); + /* Setup EAPOL state machines to already authenticated state + * because of existing FT information from R0KH. */ + sta->eapol_sm->keyRun = TRUE; + sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; + sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; + sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; + sta->eapol_sm->authSuccess = TRUE; + sta->eapol_sm->authFail = FALSE; + if (sta->eapol_sm->eap) + eap_sm_notify_cached(sta->eapol_sm->eap); + /* TODO: get vlan_id from R0KH using RRB message */ + return; + } +#endif /* CONFIG_IEEE80211R */ + pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); if (pmksa) { int old_vlanid; @@ -885,6 +1036,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; sta->eapol_sm->authSuccess = TRUE; + sta->eapol_sm->authFail = FALSE; if (sta->eapol_sm->eap) eap_sm_notify_cached(sta->eapol_sm->eap); old_vlanid = sta->vlan_id; @@ -918,6 +1070,7 @@ void ieee802_1x_free_station(struct sta_info *sta) #ifndef CONFIG_NO_RADIUS radius_msg_free(sm->last_recv_radius); radius_free_class(&sm->radius_class); + wpabuf_free(sm->radius_cui); #endif /* CONFIG_NO_RADIUS */ os_free(sm->identity); @@ -929,9 +1082,8 @@ void ieee802_1x_free_station(struct sta_info *sta) static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, struct sta_info *sta) { - u8 *eap; - size_t len; - struct eap_hdr *hdr; + struct wpabuf *eap; + const struct eap_hdr *hdr; int eap_type = -1; char buf[64]; struct radius_msg *msg; @@ -945,7 +1097,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, msg = sm->last_recv_radius; - eap = radius_msg_get_eap(msg, &len); + eap = radius_msg_get_eap(msg); if (eap == NULL) { /* RFC 3579, Chap. 2.6.3: * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message @@ -957,19 +1109,19 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, return; } - if (len < sizeof(*hdr)) { + if (wpabuf_len(eap) < sizeof(*hdr)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_WARNING, "too short EAP packet " "received from authentication server"); - os_free(eap); + wpabuf_free(eap); sm->eap_if->aaaEapNoReq = TRUE; return; } - if (len > sizeof(*hdr)) - eap_type = eap[sizeof(*hdr)]; + if (wpabuf_len(eap) > sizeof(*hdr)) + eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; - hdr = (struct eap_hdr *) eap; + hdr = wpabuf_head(eap); switch (hdr->code) { case EAP_CODE_REQUEST: if (eap_type >= 0) @@ -1004,7 +1156,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, sm->eap_if->aaaEapReq = TRUE; wpabuf_free(sm->eap_if->aaaEapReqData); - sm->eap_if->aaaEapReqData = wpabuf_alloc_ext_data(eap, len); + sm->eap_if->aaaEapReqData = eap; } @@ -1069,7 +1221,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, if (count <= 0) return; - nclass = os_zalloc(count * sizeof(struct radius_attr_data)); + nclass = os_calloc(count, sizeof(struct radius_attr_data)); if (nclass == NULL) return; @@ -1139,6 +1291,32 @@ static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, } +/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */ +static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd, + struct sta_info *sta, + struct radius_msg *msg) +{ + struct eapol_state_machine *sm = sta->eapol_sm; + struct wpabuf *cui; + u8 *buf; + size_t len; + + if (sm == NULL) + return; + + if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, + &buf, &len, NULL) < 0) + return; + + cui = wpabuf_alloc_copy(buf, len); + if (cui == NULL) + return; + + wpabuf_free(sm->radius_cui); + sm->radius_cui = cui; +} + + struct sta_id_search { u8 identifier; struct eapol_state_machine *sm; @@ -1298,6 +1476,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, shared_secret_len); ieee802_1x_store_radius_class(hapd, sta, msg); ieee802_1x_update_sta_identity(hapd, sta, msg); + ieee802_1x_update_sta_cui(hapd, sta, msg); if (sm->eap_if->eapKeyAvailable && wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt, session_timeout_set ? @@ -1363,6 +1542,9 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) * request and we cannot continue EAP processing (EAP-Failure * could only be sent if the EAP peer actually replied). */ + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR, + MAC2STR(sta->addr)); + sm->eap_if->portEnabled = FALSE; ap_sta_disconnect(hapd, sta, sta->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); @@ -1380,8 +1562,8 @@ static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) os_free(eapol->default_wep_key); eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); if (eapol->default_wep_key == NULL || - os_get_random(eapol->default_wep_key, - hapd->conf->default_wep_key_len)) { + random_get_bytes(eapol->default_wep_key, + hapd->conf->default_wep_key_len)) { printf("Could not generate random WEP key.\n"); os_free(eapol->default_wep_key); eapol->default_wep_key = NULL; @@ -1432,10 +1614,11 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) /* TODO: Could setup key for RX here, but change default TX keyid only * after new broadcast key has been sent to all stations. */ - if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, NULL, - eapol->default_wep_key_idx, 1, NULL, 0, - eapol->default_wep_key, - hapd->conf->default_wep_key_len)) { + if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, + broadcast_ether_addr, + eapol->default_wep_key_idx, 1, NULL, 0, + eapol->default_wep_key, + hapd->conf->default_wep_key_len)) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_WARNING, "failed to configure a " "new broadcast key"); @@ -1514,19 +1697,15 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, { struct hostapd_data *hapd = ctx; const struct hostapd_eap_user *eap_user; - int i, count; + int i; - eap_user = hostapd_get_eap_user(hapd->conf, identity, - identity_len, phase2); + eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); if (eap_user == NULL) return -1; os_memset(user, 0, sizeof(*user)); user->phase2 = phase2; - count = EAP_USER_MAX_METHODS; - if (count > EAP_MAX_METHODS) - count = EAP_MAX_METHODS; - for (i = 0; i < count; i++) { + for (i = 0; i < EAP_MAX_METHODS; i++) { user->methods[i].vendor = eap_user->methods[i].vendor; user->methods[i].method = eap_user->methods[i].method; } @@ -1538,6 +1717,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, os_memcpy(user->password, eap_user->password, eap_user->password_len); user->password_len = eap_user->password_len; + user->password_hash = eap_user->password_hash; } user->force_version = eap_user->force_version; user->ttls_auth = eap_user->ttls_auth; @@ -1651,6 +1831,9 @@ int ieee802_1x_init(struct hostapd_data *hapd) conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; conf.tnc = hapd->conf->tnc; conf.wps = hapd->wps; + conf.fragment_size = hapd->conf->fragment_size; + conf.pwd_group = hapd->conf->pwd_group; + conf.pbc_in_m1 = hapd->conf->pbc_in_m1; os_memset(&cb, 0, sizeof(cb)); cb.eapol_send = ieee802_1x_eapol_send; @@ -1669,7 +1852,7 @@ int ieee802_1x_init(struct hostapd_data *hapd) return -1; if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && - hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) + hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) return -1; #ifndef CONFIG_NO_RADIUS @@ -1680,9 +1863,9 @@ int ieee802_1x_init(struct hostapd_data *hapd) if (hapd->conf->default_wep_key_len) { for (i = 0; i < 4; i++) - hapd->drv.set_key(hapd->conf->iface, hapd, - WPA_ALG_NONE, NULL, i, 0, NULL, 0, - NULL, 0); + hostapd_drv_set_key(hapd->conf->iface, hapd, + WPA_ALG_NONE, NULL, i, 0, NULL, 0, + NULL, 0); ieee802_1x_rekey(hapd, NULL); @@ -1700,7 +1883,7 @@ void ieee802_1x_deinit(struct hostapd_data *hapd) if (hapd->driver != NULL && (hapd->conf->ieee802_1x || hapd->conf->wpa)) - hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 0); + hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); eapol_auth_deinit(hapd->eapol_auth); hapd->eapol_auth = NULL; @@ -1711,15 +1894,13 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, const u8 *buf, size_t len, int ack) { struct ieee80211_hdr *hdr; - struct ieee802_1x_hdr *xhdr; - struct ieee802_1x_eapol_key *key; u8 *pos; const unsigned char rfc1042_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; if (sta == NULL) return -1; - if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr)) + if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2) return 0; hdr = (struct ieee80211_hdr *) buf; @@ -1731,21 +1912,44 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, return 0; pos += 2; - xhdr = (struct ieee802_1x_hdr *) pos; - pos += sizeof(*xhdr); + return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos, + ack); +} + + +int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *buf, int len, int ack) +{ + const struct ieee802_1x_hdr *xhdr = + (const struct ieee802_1x_hdr *) buf; + const u8 *pos = buf + sizeof(*xhdr); + struct ieee802_1x_eapol_key *key; + if (len < (int) sizeof(*xhdr)) + return 0; wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " "type=%d length=%d - ack=%d", MAC2STR(sta->addr), xhdr->version, xhdr->type, be_to_host16(xhdr->length), ack); + if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) + return 0; + + if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { + const struct wpa_eapol_key *wpa; + wpa = (const struct wpa_eapol_key *) pos; + if (wpa->type == EAPOL_KEY_TYPE_RSN || + wpa->type == EAPOL_KEY_TYPE_WPA) + wpa_auth_eapol_key_tx_status(hapd->wpa_auth, + sta->wpa_sm, ack); + } + /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant * or Authenticator state machines, but EAPOL-Key packets are not - * retransmitted in case of failure. Try to re-sent failed EAPOL-Key + * retransmitted in case of failure. Try to re-send failed EAPOL-Key * packets couple of times because otherwise STA keys become * unsynchronized with AP. */ - if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack && - pos + sizeof(*key) <= buf + len) { + if (!ack && pos + sizeof(*key) <= buf + len) { key = (struct ieee802_1x_eapol_key *) pos; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " @@ -1789,8 +1993,17 @@ u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, } +struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm) +{ + if (sm == NULL) + return NULL; + return sm->radius_cui; +} + + const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) { + *len = 0; if (sm == NULL) return NULL; @@ -1848,6 +2061,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, { int len = 0, ret; struct eapol_state_machine *sm = sta->eapol_sm; + struct os_time t; if (sm == NULL) return 0; @@ -1962,6 +2176,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, len += ret; /* dot1xAuthSessionStatsTable */ + os_get_time(&t); ret = os_snprintf(buf + len, buflen - len, /* TODO: dot1xAuthSessionOctetsRx */ /* TODO: dot1xAuthSessionOctetsTx */ @@ -1976,8 +2191,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, (wpa_key_mgmt_wpa_ieee8021x( wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 1 : 2, - (unsigned int) (time(NULL) - - sta->acct_session_start), + (unsigned int) (t.sec - sta->acct_session_start), sm->identity); if (ret < 0 || (size_t) ret >= buflen - len) return len; @@ -2004,22 +2218,25 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, "Added PMKSA cache entry (IEEE 802.1X)"); } -#ifdef CONFIG_WPS - if (!success && (sta->flags & WLAN_STA_WPS)) { + if (!success) { /* * Many devices require deauthentication after WPS provisioning * and some may not be be able to do that themselves, so - * disconnect the client here. + * disconnect the client here. In addition, this may also + * benefit IEEE 802.1X/EAPOL authentication cases, too since + * the EAPOL PAE state machine would remain in HELD state for + * considerable amount of time and some EAP methods, like + * EAP-FAST with anonymous provisioning, may require another + * EAPOL authentication to be started to complete connection. */ - wpa_printf(MSG_DEBUG, "WPS: Force disconnection after " - "EAP-Failure"); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force " + "disconnection after EAP-Failure"); /* Add a small sleep to increase likelihood of previously * requested EAP-Failure TX getting out before this should the * driver reorder operations. */ os_sleep(0, 10000); ap_sta_disconnect(hapd, sta, sta->addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); + WLAN_REASON_IEEE_802_1X_AUTH_FAILED); } -#endif /* CONFIG_WPS */ } |