From a14896e8bb69a6b2593b482e920285c83f21519b Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 23 Jul 2013 21:25:21 +0300 Subject: [PATCH] HS 2.0R2 AP: Add OSEN implementation Signed-hostap: Jouni Malinen --- hostapd/config_file.c | 2 + hostapd/hostapd.conf | 3 ++ src/ap/ap_config.c | 5 +++ src/ap/ap_config.h | 4 +- src/ap/ap_drv_ops.c | 11 ++++++ src/ap/beacon.c | 6 +++ src/ap/drv_callbacks.c | 29 ++++++++++++++ src/ap/hostapd.c | 4 +- src/ap/hs20.c | 54 +++++++++++++++++++++++++- src/ap/hs20.h | 3 +- src/ap/ieee802_11.c | 30 +++++++++++++- src/ap/ieee802_1x.c | 11 +++--- src/ap/wpa_auth.c | 13 ++++++- src/ap/wpa_auth.h | 3 ++ src/ap/wpa_auth_glue.c | 13 +++++++ src/ap/wpa_auth_ie.c | 88 ++++++++++++++++++++++++++++++++++++++++++ src/ap/wpa_auth_ie.h | 3 ++ src/drivers/driver.h | 5 +++ src/rsn_supp/wpa.c | 32 ++++++++------- 19 files changed, 294 insertions(+), 25 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 26f52e9f7..d38c3f836 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2810,6 +2810,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->hs20 = atoi(pos); } else if (os_strcmp(buf, "disable_dgaf") == 0) { bss->disable_dgaf = atoi(pos); + } else if (os_strcmp(buf, "osen") == 0) { + bss->osen = atoi(pos); } else if (os_strcmp(buf, "anqp_domain_id") == 0) { bss->anqp_domain_id = atoi(pos); } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) { diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 0630320d1..332cee0fd 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1582,6 +1582,9 @@ own_ip_addr=127.0.0.1 # forging such frames to other stations in the BSS. #disable_dgaf=1 +# OSU Server-Only Authenticated L2 Encryption Network +#osen=1 + # ANQP Domain ID (0..65535) # An identifier for a set of APs in an ESS that share the same common ANQP # information. 0 = Some of the ANQP information is unique to this AP (default). diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index f5014a5cc..cb5d3aab8 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -890,6 +890,11 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss) bss->wpa_group = cipher; bss->wpa_pairwise = cipher; bss->rsn_pairwise = cipher; + } else if (bss->osen) { + bss->ssid.security_policy = SECURITY_OSEN; + bss->wpa_group = WPA_CIPHER_CCMP; + bss->wpa_pairwise = 0; + bss->rsn_pairwise = WPA_CIPHER_CCMP; } else { bss->ssid.security_policy = SECURITY_PLAINTEXT; bss->wpa_group = WPA_CIPHER_NONE; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index b6e8cbcce..73645cdd5 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -45,7 +45,8 @@ typedef enum hostap_security_policy { SECURITY_STATIC_WEP = 1, SECURITY_IEEE_802_1X = 2, SECURITY_WPA_PSK = 3, - SECURITY_WPA = 4 + SECURITY_WPA = 4, + SECURITY_OSEN = 5 } secpolicy; struct hostapd_ssid { @@ -452,6 +453,7 @@ struct hostapd_bss_config { u8 qos_map_set[16 + 2 * 21]; unsigned int qos_map_set_len; + int osen; #ifdef CONFIG_HS20 int hs20; int disable_dgaf; diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index e998fc620..b8b260aaf 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -170,6 +170,17 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, goto fail; wpabuf_put_data(proberesp, buf, pos - buf); } + + pos = hostapd_eid_osen(hapd, buf); + if (pos != buf) { + if (wpabuf_resize(&beacon, pos - buf) != 0) + goto fail; + wpabuf_put_data(beacon, buf, pos - buf); + + if (wpabuf_resize(&proberesp, pos - buf) != 0) + goto fail; + wpabuf_put_data(proberesp, buf, pos - buf); + } #endif /* CONFIG_HS20 */ if (hapd->conf->vendor_elements) { diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 33320bd48..e06ce778d 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -442,6 +442,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, #ifdef CONFIG_HS20 pos = hostapd_eid_hs20_indication(hapd, pos); + pos = hostapd_eid_osen(hapd, pos); #endif /* CONFIG_HS20 */ if (hapd->conf->vendor_elements) { @@ -854,6 +855,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, #ifdef CONFIG_HS20 tailpos = hostapd_eid_hs20_indication(hapd, tailpos); + tailpos = hostapd_eid_osen(hapd, tailpos); #endif /* CONFIG_HS20 */ if (hapd->conf->vendor_elements) { @@ -925,6 +927,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, params->ap_max_inactivity = hapd->conf->ap_max_inactivity; #ifdef CONFIG_HS20 params->disable_dgaf = hapd->conf->disable_dgaf; + if (hapd->conf->osen) { + params->privacy = 1; + params->osen = 1; + } #endif /* CONFIG_HS20 */ return 0; } diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 9af964686..6fb105662 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -78,6 +78,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, ie = elems.wpa_ie - 2; ielen = elems.wpa_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); +#ifdef CONFIG_HS20 + } else if (elems.osen) { + ie = elems.osen - 2; + ielen = elems.osen_len + 2; + wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq"); +#endif /* CONFIG_HS20 */ } else { ie = NULL; ielen = 0; @@ -281,6 +287,29 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, sta->flags |= WLAN_STA_MAYBE_WPS; wpabuf_free(wps); #endif /* CONFIG_WPS */ +#ifdef CONFIG_HS20 + } else if (hapd->conf->osen) { + if (elems.osen == NULL) { + hostapd_logger( + hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "No HS 2.0 OSEN element in association request"); + return WLAN_STATUS_INVALID_IE; + } + + wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association"); + if (sta->wpa_sm == NULL) + sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, + sta->addr, NULL); + if (sta->wpa_sm == NULL) { + wpa_printf(MSG_WARNING, "Failed to initialize WPA " + "state machine"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, + elems.osen - 2, elems.osen_len + 2) < 0) + return WLAN_STATUS_INVALID_IE; +#endif /* CONFIG_HS20 */ } #ifdef CONFIG_WPS skip_wpa_check: diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 98148da46..75baec0e8 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -87,7 +87,7 @@ static void hostapd_reload_bss(struct hostapd_data *hapd) else hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); - if (hapd->conf->wpa && hapd->wpa_auth == NULL) { + if ((hapd->conf->wpa || hapd->conf->osen) && hapd->wpa_auth == NULL) { hostapd_setup_wpa(hapd); if (hapd->wpa_auth) wpa_init_keys(hapd->wpa_auth); @@ -802,7 +802,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - if (hapd->conf->wpa && hostapd_setup_wpa(hapd)) + if ((hapd->conf->wpa || hapd->conf->osen) && hostapd_setup_wpa(hapd)) return -1; if (accounting_init(hapd)) { diff --git a/src/ap/hs20.c b/src/ap/hs20.c index 5875b4096..d521d2cef 100644 --- a/src/ap/hs20.c +++ b/src/ap/hs20.c @@ -1,7 +1,7 @@ /* * Hotspot 2.0 AP ANQP processing * Copyright (c) 2009, Atheros Communications, Inc. - * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -39,6 +39,58 @@ u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid) } +u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid) +{ + u8 *len; + u16 capab; + + if (!hapd->conf->osen) + return eid; + + *eid++ = WLAN_EID_VENDOR_SPECIFIC; + len = eid++; /* to be filled */ + WPA_PUT_BE24(eid, OUI_WFA); + eid += 3; + *eid++ = HS20_OSEN_OUI_TYPE; + + /* Group Data Cipher Suite */ + RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); + eid += RSN_SELECTOR_LEN; + + /* Pairwise Cipher Suite Count and List */ + WPA_PUT_LE16(eid, 1); + eid += 2; + RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP); + eid += RSN_SELECTOR_LEN; + + /* AKM Suite Count and List */ + WPA_PUT_LE16(eid, 1); + eid += 2; + RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN); + eid += RSN_SELECTOR_LEN; + + /* RSN Capabilities */ + capab = 0; + if (hapd->conf->wmm_enabled) { + /* 4 PTKSA replay counters when using WMM */ + capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); + } +#ifdef CONFIG_IEEE80211W + if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { + capab |= WPA_CAPABILITY_MFPC; + if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) + capab |= WPA_CAPABILITY_MFPR; + } +#endif /* CONFIG_IEEE80211W */ + WPA_PUT_LE16(eid, capab); + eid += 2; + + *len = eid - len - 1; + + return eid; +} + + int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr, u8 osu_method, const char *url) { diff --git a/src/ap/hs20.h b/src/ap/hs20.h index 059764e47..c7ffa3687 100644 --- a/src/ap/hs20.h +++ b/src/ap/hs20.h @@ -1,6 +1,6 @@ /* * Hotspot 2.0 AP ANQP processing - * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -12,6 +12,7 @@ struct hostapd_data; u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid); int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr, u8 osu_method, const char *url); diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index f3e0df313..3e704e561 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -162,6 +162,11 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, if (hapd->conf->wpa) privacy = 1; +#ifdef CONFIG_HS20 + if (hapd->conf->osen) + privacy = 1; +#endif /* CONFIG_HS20 */ + if (sta) { int policy, def_klen; if (probe && sta->ssid_probe) { @@ -1089,6 +1094,29 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; } #endif /* CONFIG_IEEE80211N */ +#ifdef CONFIG_HS20 + } else if (hapd->conf->osen) { + if (elems.osen == NULL) { + hostapd_logger( + hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "No HS 2.0 OSEN element in association request"); + return WLAN_STATUS_INVALID_IE; + } + + wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association"); + if (sta->wpa_sm == NULL) + sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, + sta->addr, NULL); + if (sta->wpa_sm == NULL) { + wpa_printf(MSG_WARNING, "Failed to initialize WPA " + "state machine"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, + elems.osen - 2, elems.osen_len + 2) < 0) + return WLAN_STATUS_INVALID_IE; +#endif /* CONFIG_HS20 */ } else wpa_auth_sta_no_wpa(sta->wpa_sm); @@ -1924,7 +1952,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, new_assoc = 0; sta->flags |= WLAN_STA_ASSOC; sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; - if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || + if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) || sta->auth_alg == WLAN_AUTH_FT) { /* * Open, static WEP, or FT protocol; no separate authorization diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 97ba601b3..f07b6bf87 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -686,7 +686,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, struct rsn_pmksa_cache_entry *pmksa; int key_mgmt; - if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && + if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen && !hapd->conf->wps_state) return; @@ -737,7 +737,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, return; } - if (!hapd->conf->ieee802_1x && + if (!hapd->conf->ieee802_1x && !hapd->conf->osen && !(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"); @@ -757,7 +757,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, return; #ifdef CONFIG_WPS - if (!hapd->conf->ieee802_1x) { + if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) { u32 wflags = sta->flags & (WLAN_STA_WPS | WLAN_STA_WPS2 | WLAN_STA_MAYBE_WPS); @@ -875,7 +875,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) } #endif /* CONFIG_WPS */ - if (!force_1x && !hapd->conf->ieee802_1x) { + if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) { wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - " "802.1X not enabled or forced for WPS"); /* @@ -913,7 +913,8 @@ 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_WPS2)) { + if (!hapd->conf->ieee802_1x && hapd->conf->wps_state && + !(sta->flags & WLAN_STA_WPS2)) { /* * Delay EAPOL frame transmission until a possible WPS STA * initiates the handshake with EAPOL-Start. Only allow the diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 707a63f0c..cc64ff181 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -211,6 +211,8 @@ static int wpa_use_aes_cmac(struct wpa_state_machine *sm) if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt)) ret = 1; #endif /* CONFIG_IEEE80211W */ + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) + ret = 1; return ret; } @@ -878,6 +880,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, if (sm->pairwise == WPA_CIPHER_CCMP || sm->pairwise == WPA_CIPHER_GCMP) { if (wpa_use_aes_cmac(sm) && + sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN && ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, @@ -1001,6 +1004,9 @@ continue_processing: if (kde.rsn_ie) { eapol_key_ie = kde.rsn_ie; eapol_key_ie_len = kde.rsn_ie_len; + } else if (kde.osen) { + eapol_key_ie = kde.osen; + eapol_key_ie_len = kde.osen_len; } else { eapol_key_ie = kde.wpa_ie; eapol_key_ie_len = kde.wpa_ie_len; @@ -1286,6 +1292,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, if (force_version) version = force_version; + else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) + version = WPA_KEY_INFO_TYPE_AKM_DEFINED; else if (wpa_use_aes_cmac(sm)) version = WPA_KEY_INFO_TYPE_AES_128_CMAC; else if (sm->pairwise != WPA_CIPHER_TKIP) @@ -1308,6 +1316,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, key_data_len = kde_len; if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || + sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) { pad_len = key_data_len % 8; if (pad_len) @@ -1376,6 +1385,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data", buf, key_data_len); if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || + sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf, (u8 *) (key + 1))) { @@ -1774,7 +1784,8 @@ SM_STATE(WPA_PTK, PTKSTART) * one possible PSK for this STA. */ if (sm->wpa == WPA_VERSION_WPA2 && - wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) { + wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) && + sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN) { pmkid = buf; pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; pmkid[0] = WLAN_EID_VENDOR_SPECIFIC; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index bc3dec45a..d99db691b 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -232,6 +232,9 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, const u8 *wpa_ie, size_t wpa_ie_len, const u8 *mdie, size_t mdie_len); +int wpa_validate_osen(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + const u8 *osen_ie, size_t osen_ie_len); int wpa_auth_uses_mfp(struct wpa_state_machine *sm); struct wpa_state_machine * wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr, diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 5af149503..da5fea7ce 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -73,6 +73,19 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_HS20 wconf->disable_gtk = conf->disable_dgaf; + if (conf->osen) { + wconf->disable_gtk = 1; + wconf->wpa = WPA_PROTO_OSEN; + wconf->wpa_key_mgmt = WPA_KEY_MGMT_OSEN; + wconf->wpa_pairwise = 0; + wconf->wpa_group = WPA_CIPHER_CCMP; + wconf->rsn_pairwise = WPA_CIPHER_CCMP; + wconf->rsn_preauth = 0; + wconf->disable_pmksa_caching = 1; +#ifdef CONFIG_IEEE80211W + wconf->ieee80211w = 1; +#endif /* CONFIG_IEEE80211W */ + } #endif /* CONFIG_HS20 */ #ifdef CONFIG_TESTING_OPTIONS wconf->corrupt_gtk_rekey_mic_probability = diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 274f4d621..7a497516f 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -295,6 +295,55 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, } +static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid) +{ + u8 *len; + u16 capab; + + *eid++ = WLAN_EID_VENDOR_SPECIFIC; + len = eid++; /* to be filled */ + WPA_PUT_BE24(eid, OUI_WFA); + eid += 3; + *eid++ = HS20_OSEN_OUI_TYPE; + + /* Group Data Cipher Suite */ + RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); + eid += RSN_SELECTOR_LEN; + + /* Pairwise Cipher Suite Count and List */ + WPA_PUT_LE16(eid, 1); + eid += 2; + RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP); + eid += RSN_SELECTOR_LEN; + + /* AKM Suite Count and List */ + WPA_PUT_LE16(eid, 1); + eid += 2; + RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN); + eid += RSN_SELECTOR_LEN; + + /* RSN Capabilities */ + capab = 0; + if (conf->wmm_enabled) { + /* 4 PTKSA replay counters when using WMM */ + capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); + } +#ifdef CONFIG_IEEE80211W + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { + capab |= WPA_CAPABILITY_MFPC; + if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) + capab |= WPA_CAPABILITY_MFPR; + } +#endif /* CONFIG_IEEE80211W */ + WPA_PUT_LE16(eid, capab); + eid += 2; + + *len = eid - len - 1; + + return eid; +} + + int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) { u8 *pos, buf[128]; @@ -302,6 +351,9 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) pos = buf; + if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) { + pos = wpa_write_osen(&wpa_auth->conf, pos); + } if (wpa_auth->conf.wpa & WPA_PROTO_RSN) { res = wpa_write_rsn_ie(&wpa_auth->conf, pos, buf + sizeof(buf) - pos, NULL); @@ -626,6 +678,36 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } +#ifdef CONFIG_HS20 +int wpa_validate_osen(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + const u8 *osen_ie, size_t osen_ie_len) +{ + if (wpa_auth == NULL || sm == NULL) + return -1; + + /* TODO: parse OSEN element */ + sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN; + sm->mgmt_frame_prot = 1; + sm->pairwise = WPA_CIPHER_CCMP; + sm->wpa = WPA_VERSION_WPA2; + + if (sm->wpa_ie == NULL || sm->wpa_ie_len < osen_ie_len) { + os_free(sm->wpa_ie); + sm->wpa_ie = os_malloc(osen_ie_len); + if (sm->wpa_ie == NULL) + return -1; + } + + os_memcpy(sm->wpa_ie, osen_ie, osen_ie_len); + sm->wpa_ie_len = osen_ie_len; + + return 0; +} + +#endif /* CONFIG_HS20 */ + + /** * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs * @pos: Pointer to the IE header @@ -648,6 +730,12 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, return 0; } + if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) { + ie->osen = pos; + ie->osen_len = pos[1] + 2; + return 0; + } + if (pos + 1 + RSN_SELECTOR_LEN < end && pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h index f94588252..d2067ba31 100644 --- a/src/ap/wpa_auth_ie.h +++ b/src/ap/wpa_auth_ie.h @@ -43,6 +43,9 @@ struct wpa_eapol_ie_parse { const u8 *ip_addr_req; const u8 *ip_addr_alloc; #endif /* CONFIG_P2P */ + + const u8 *osen; + size_t osen_len; }; int wpa_parse_kde_ies(const u8 *buf, size_t len, diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 69e837a1f..d2aad246b 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -847,6 +847,11 @@ struct wpa_driver_ap_params { * disable_dgaf - Whether group-addressed frames are disabled */ int disable_dgaf; + + /** + * osen - Whether OSEN security is enabled + */ + int osen; }; /** diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 0a6f0d834..ba50263dd 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -110,7 +110,8 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) if (rbuf == NULL) return; - reply->type = sm->proto == WPA_PROTO_RSN ? + reply->type = (sm->proto == WPA_PROTO_RSN || + sm->proto == WPA_PROTO_OSEN) ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; key_info = WPA_KEY_INFO_REQUEST | ver; if (sm->ptk_set) @@ -234,7 +235,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, } if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && - !wpa_key_mgmt_ft(sm->key_mgmt)) { + !wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN) + { /* Send EAPOL-Start to trigger full EAP authentication. */ u8 *buf; size_t buflen; @@ -328,11 +330,12 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, return -1; } - reply->type = sm->proto == WPA_PROTO_RSN ? + reply->type = (sm->proto == WPA_PROTO_RSN || + sm->proto == WPA_PROTO_OSEN) ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; WPA_PUT_BE16(reply->key_info, ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC); - if (sm->proto == WPA_PROTO_RSN) + if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) WPA_PUT_BE16(reply->key_length, 0); else os_memcpy(reply->key_length, key->key_length, 2); @@ -397,7 +400,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, os_memset(&ie, 0, sizeof(ie)); - if (sm->proto == WPA_PROTO_RSN) { + if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) { /* RSN: msg 1/4 should contain PMKID for the selected PMK */ const u8 *_buf = (const u8 *) (key + 1); size_t len = WPA_GET_BE16(key->key_data_length); @@ -564,7 +567,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, keylen = wpa_cipher_key_len(sm->pairwise_cipher); rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher); - if (sm->proto == WPA_PROTO_RSN) { + if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) { key_rsc = null_rsc; } else { key_rsc = key->key_rsc; @@ -1036,12 +1039,13 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, if (rbuf == NULL) return -1; - reply->type = sm->proto == WPA_PROTO_RSN ? + reply->type = (sm->proto == WPA_PROTO_RSN || + sm->proto == WPA_PROTO_OSEN) ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; key_info &= WPA_KEY_INFO_SECURE; key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC; WPA_PUT_BE16(reply->key_info, key_info); - if (sm->proto == WPA_PROTO_RSN) + if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) WPA_PUT_BE16(reply->key_length, 0); else os_memcpy(reply->key_length, key->key_length, 2); @@ -1323,12 +1327,13 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, if (rbuf == NULL) return -1; - reply->type = sm->proto == WPA_PROTO_RSN ? + reply->type = (sm->proto == WPA_PROTO_RSN || + sm->proto == WPA_PROTO_OSEN) ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; key_info &= WPA_KEY_INFO_KEY_INDEX_MASK; key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; WPA_PUT_BE16(reply->key_info, key_info); - if (sm->proto == WPA_PROTO_RSN) + if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) WPA_PUT_BE16(reply->key_length, 0); else os_memcpy(reply->key_length, key->key_length, 2); @@ -1363,7 +1368,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, key_info = WPA_GET_BE16(key->key_info); keydatalen = WPA_GET_BE16(key->key_data_length); - if (sm->proto == WPA_PROTO_RSN) { + if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) { ret = wpa_supplicant_process_1_of_2_rsn(sm, (const u8 *) (key + 1), keydatalen, key_info, @@ -1811,7 +1816,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, } extra_len = WPA_GET_BE16(key->key_data_length); - if (sm->proto == WPA_PROTO_RSN && + if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { if (wpa_supplicant_decrypt_key_data(sm, key, ver)) goto out; @@ -1865,7 +1870,8 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm) { switch (sm->key_mgmt) { case WPA_KEY_MGMT_IEEE8021X: - return (sm->proto == WPA_PROTO_RSN ? + return ((sm->proto == WPA_PROTO_RSN || + sm->proto == WPA_PROTO_OSEN) ? RSN_AUTH_KEY_MGMT_UNSPEC_802_1X : WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); case WPA_KEY_MGMT_PSK: