diff --git a/contrib/hostapd/eap.c b/contrib/hostapd/eap.c index 7a21c802e5a4..1897856e8820 100644 --- a/contrib/hostapd/eap.c +++ b/contrib/hostapd/eap.c @@ -10,6 +10,8 @@ * license. * * See README and COPYING for more details. + * + * $FreeBSD$ */ #include @@ -909,3 +911,11 @@ void eap_sm_deinit(struct eap_sm *sm) eap_user_free(sm->user); free(sm); } + +void eap_sm_notify_cached(struct eap_sm *sm) +{ + if (sm == NULL) + return; + + sm->EAP_state = EAP_SUCCESS; +} diff --git a/contrib/hostapd/eap.h b/contrib/hostapd/eap.h index 01f47dad12e4..c79bffece50f 100644 --- a/contrib/hostapd/eap.h +++ b/contrib/hostapd/eap.h @@ -1,3 +1,5 @@ +/* $FreeBSD$ */ + #ifndef EAP_H #define EAP_H @@ -48,6 +50,7 @@ int eap_sm_step(struct eap_sm *sm); u8 eap_get_type(const char *name); void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData, size_t eapRespDataLen); +void eap_sm_notify_cached(struct eap_sm *sm); #else /* EAP_AUTHENTICATOR */ @@ -78,6 +81,10 @@ static inline void eap_set_eapRespData(struct eap_sm *sm, { } +static inline void eap_sm_notify_cached(struct eap_sm *sm) +{ +} + #endif /* EAP_AUTHENTICATOR */ #endif /* EAP_H */ diff --git a/contrib/hostapd/eapol_sm.c b/contrib/hostapd/eapol_sm.c index fce7c6d3391a..2ae17545b156 100644 --- a/contrib/hostapd/eapol_sm.c +++ b/contrib/hostapd/eapol_sm.c @@ -11,6 +11,8 @@ * license. * * See README and COPYING for more details. + * + * $FreeBSD$ */ #include @@ -124,6 +126,8 @@ SM_STATE(AUTH_PAE, DISCONNECTED) if (!from_initialize) { if (sm->flags & EAPOL_SM_PREAUTH) rsn_preauth_finished(sm->hapd, sm->sta, 0); + else + ieee802_1x_finished(sm->hapd, sm->sta, 0); } } @@ -174,6 +178,8 @@ SM_STATE(AUTH_PAE, HELD) HOSTAPD_LEVEL_WARNING, "authentication failed"); if (sm->flags & EAPOL_SM_PREAUTH) rsn_preauth_finished(sm->hapd, sm->sta, 0); + else + ieee802_1x_finished(sm->hapd, sm->sta, 0); } @@ -191,6 +197,8 @@ SM_STATE(AUTH_PAE, AUTHENTICATED) HOSTAPD_LEVEL_INFO, "authenticated"); if (sm->flags & EAPOL_SM_PREAUTH) rsn_preauth_finished(sm->hapd, sm->sta, 1); + else + ieee802_1x_finished(sm->hapd, sm->sta, 1); } diff --git a/contrib/hostapd/ieee802_1x.c b/contrib/hostapd/ieee802_1x.c index 870d52ab5cac..956664aa3c2e 100644 --- a/contrib/hostapd/ieee802_1x.c +++ b/contrib/hostapd/ieee802_1x.c @@ -11,6 +11,8 @@ * license. * * See README and COPYING for more details. + * + * $FreeBSD$ */ #include @@ -755,7 +757,6 @@ void ieee802_1x_receive(hostapd *hapd, u8 *sa, u8 *buf, size_t len) sta->eapol_sm->auth_pae.eapolStart = TRUE; sta->eapol_sm->dot1xAuthEapolStartFramesRx++; wpa_sm_event(hapd, sta, WPA_REAUTH_EAPOL); - eapol_sm_step(sta->eapol_sm); break; case IEEE802_1X_TYPE_EAPOL_LOGOFF: @@ -766,7 +767,6 @@ void ieee802_1x_receive(hostapd *hapd, u8 *sa, u8 *buf, size_t len) RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; sta->eapol_sm->auth_pae.eapolLogoff = TRUE; sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; - eapol_sm_step(sta->eapol_sm); break; case IEEE802_1X_TYPE_EAPOL_KEY: @@ -809,8 +809,29 @@ void ieee802_1x_new_station(hostapd *hapd, struct sta_info *sta) hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "start authentication"); sta->eapol_sm = eapol_sm_alloc(hapd, sta); - if (sta->eapol_sm) - sta->eapol_sm->portEnabled = TRUE; + if (sta->eapol_sm == NULL) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, + HOSTAPD_LEVEL_INFO, "failed to allocate " + "state machine"); + return; + } + + sta->eapol_sm->portEnabled = TRUE; + + if (sta->pmksa) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, + HOSTAPD_LEVEL_DEBUG, + "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); + /* Setup EAPOL state machines to already authenticated state + * because of existing PMKSA information in the cache. */ + sta->eapol_sm->keyRun = TRUE; + sta->eapol_sm->keyAvailable = TRUE; + sta->eapol_sm->auth_pae.state = AUTH_PAE_AUTHENTICATING; + sta->eapol_sm->be_auth.state = BE_AUTH_SUCCESS; + sta->eapol_sm->authSuccess = TRUE; + if (sta->eapol_sm->eap) + eap_sm_notify_cached(sta->eapol_sm->eap); + } } @@ -1647,3 +1668,18 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, return len; } + +void ieee802_1x_finished(struct hostapd_data *hapd, struct sta_info *sta, + int success) +{ + u8 *key; + size_t len; + /* TODO: get PMKLifetime from WPA parameters */ + static const int dot11RSNAConfigPMKLifetime = 43200; + + key = ieee802_1x_get_key_crypt(sta->eapol_sm, &len); + if (success && key) { + pmksa_cache_add(hapd, sta, key, dot11RSNAConfigPMKLifetime); + } +} + diff --git a/contrib/hostapd/ieee802_1x.h b/contrib/hostapd/ieee802_1x.h index 3916138c0b41..9d2567a5b667 100644 --- a/contrib/hostapd/ieee802_1x.h +++ b/contrib/hostapd/ieee802_1x.h @@ -1,3 +1,5 @@ +/* $FreeBSD$ */ + #ifndef IEEE802_1X_H #define IEEE802_1X_H @@ -10,7 +12,13 @@ struct ieee802_1x_hdr { /* followed by length octets of data */ } __attribute__ ((packed)); + +#if defined(IEEE802_1X_EAPOL_VERSION_2) #define EAPOL_VERSION 2 +#else +/* Enable support for older Authenticators/Supplicants using EAPOL Version 1 */ +#define EAPOL_VERSION 1 +#endif /* ! IEEE802_1X_EAPOL_VERSION_2 */ enum { IEEE802_1X_TYPE_EAP_PACKET = 0, IEEE802_1X_TYPE_EAPOL_START = 1, @@ -80,5 +88,7 @@ int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen); int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, char *buf, size_t buflen); void hostapd_get_ntp_timestamp(u8 *buf); +void ieee802_1x_finished(struct hostapd_data *hapd, struct sta_info *sta, + int success); #endif /* IEEE802_1X_H */ diff --git a/contrib/hostapd/wpa.c b/contrib/hostapd/wpa.c index 8beab8deaadc..e357a858b1df 100644 --- a/contrib/hostapd/wpa.c +++ b/contrib/hostapd/wpa.c @@ -11,6 +11,8 @@ * license. * * See README and COPYING for more details. + * + * $FreeBSD$ */ #include @@ -1945,20 +1947,6 @@ void wpa_sm_event(struct hostapd_data *hapd, struct sta_info *sta, break; } - if ((event == WPA_ASSOC || event == WPA_REAUTH) && - sta->eapol_sm && sta->pmksa) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, - HOSTAPD_LEVEL_DEBUG, - "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); - /* Setup EAPOL state machines to already authenticated state - * because of existing PMKSA information in the cache. */ - sta->eapol_sm->keyRun = TRUE; - sta->eapol_sm->keyAvailable = TRUE; - sta->eapol_sm->auth_pae.state = AUTH_PAE_AUTHENTICATING; - sta->eapol_sm->be_auth.state = BE_AUTH_SUCCESS; - sta->eapol_sm->authSuccess = TRUE; - } - sm->PTK_valid = FALSE; memset(&sm->PTK, 0, sizeof(sm->PTK));