From df0f01d91f56fc55fedfd78a81a1fcca031af537 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 23 Jul 2013 21:24:05 +0300 Subject: [PATCH] HS 2.0R2: Add OSEN client implementation Signed-hostap: Jouni Malinen --- src/rsn_supp/wpa.c | 22 +++++++++-- src/rsn_supp/wpa_ie.c | 65 +++++++++++++++++++++++++++++++++ wpa_supplicant/config.c | 6 +++ wpa_supplicant/events.c | 26 +++++++++++-- wpa_supplicant/sme.c | 4 ++ wpa_supplicant/wpa_supplicant.c | 25 +++++++++++-- 6 files changed, 137 insertions(+), 11 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 4474c3b11..0a6f0d834 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -89,7 +89,10 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) int key_info, ver; u8 bssid[ETH_ALEN], *rbuf; - if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt)) + if (sm->key_mgmt == WPA_KEY_MGMT_OSEN) + ver = WPA_KEY_INFO_TYPE_AKM_DEFINED; + else if (wpa_key_mgmt_ft(sm->key_mgmt) || + wpa_key_mgmt_sha256(sm->key_mgmt)) ver = WPA_KEY_INFO_TYPE_AES_128_CMAC; else if (sm->pairwise_cipher != WPA_CIPHER_TKIP) ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; @@ -1480,7 +1483,8 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, return -1; } } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || - ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { + ver == WPA_KEY_INFO_TYPE_AES_128_CMAC || + sm->key_mgmt == WPA_KEY_MGMT_OSEN) { u8 *buf; if (keydatalen % 8) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, @@ -1662,13 +1666,22 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ - ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES && + sm->key_mgmt != WPA_KEY_MGMT_OSEN) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Unsupported EAPOL-Key descriptor version %d", ver); goto out; } + if (sm->key_mgmt == WPA_KEY_MGMT_OSEN && + ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "OSEN: Unsupported EAPOL-Key descriptor version %d", + ver); + goto out; + } + #ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->key_mgmt)) { /* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */ @@ -1681,7 +1694,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W if (wpa_key_mgmt_sha256(sm->key_mgmt)) { - if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { + if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && + sm->key_mgmt != WPA_KEY_MGMT_OSEN) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: AP did not use the " "negotiated AES-128-CMAC"); diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index e58bdc477..9c1118395 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -222,6 +222,64 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, } +#ifdef CONFIG_HS20 +static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len, + int pairwise_cipher, int group_cipher, + int key_mgmt) +{ + u8 *pos, *len; + u32 suite; + + if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN + + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN) + return -1; + + pos = wpa_ie; + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + len = pos++; /* to be filled */ + WPA_PUT_BE24(pos, OUI_WFA); + pos += 3; + *pos++ = HS20_OSEN_OUI_TYPE; + + /* Group Data Cipher Suite */ + suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); + if (suite == 0) { + wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", + group_cipher); + return -1; + } + RSN_SELECTOR_PUT(pos, suite); + pos += RSN_SELECTOR_LEN; + + /* Pairwise Cipher Suite Count and List */ + WPA_PUT_LE16(pos, 1); + pos += 2; + suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); + if (suite == 0 || + (!wpa_cipher_valid_pairwise(pairwise_cipher) && + pairwise_cipher != WPA_CIPHER_NONE)) { + wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", + pairwise_cipher); + return -1; + } + RSN_SELECTOR_PUT(pos, suite); + pos += RSN_SELECTOR_LEN; + + /* AKM Suite Count and List */ + WPA_PUT_LE16(pos, 1); + pos += 2; + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN); + pos += RSN_SELECTOR_LEN; + + *len = pos - len - 1; + + WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); + + return pos - wpa_ie; +} +#endif /* CONFIG_HS20 */ + + /** * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy * @sm: Pointer to WPA state machine data from wpa_sm_init() @@ -237,6 +295,13 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) sm->group_cipher, sm->key_mgmt, sm->mgmt_group_cipher, sm); +#ifdef CONFIG_HS20 + else if (sm->proto == WPA_PROTO_OSEN) + return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len, + sm->pairwise_cipher, + sm->group_cipher, + sm->key_mgmt); +#endif /* CONFIG_HS20 */ else return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, sm->pairwise_cipher, diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 343d7c103..6933df96d 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -405,6 +405,8 @@ static int wpa_config_parse_proto(const struct parse_data *data, else if (os_strcmp(start, "RSN") == 0 || os_strcmp(start, "WPA2") == 0) val |= WPA_PROTO_RSN; + else if (os_strcmp(start, "OSEN") == 0) + val |= WPA_PROTO_OSEN; else { wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'", line, start); @@ -516,6 +518,10 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, else if (os_strcmp(start, "FT-SAE") == 0) val |= WPA_KEY_MGMT_FT_SAE; #endif /* CONFIG_SAE */ +#ifdef CONFIG_HS20 + else if (os_strcmp(start, "OSEN") == 0) + val |= WPA_KEY_MGMT_OSEN; +#endif /* CONFIG_HS20 */ else { wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", line, start); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index abffc0829..eddd85857 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -398,6 +398,9 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss, if (wpa_key_mgmt_wpa(ssid->key_mgmt)) privacy = 1; + if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) + privacy = 1; + if (bss->caps & IEEE80211_CAP_PRIVACY) return privacy; return !privacy; @@ -539,6 +542,12 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, return 0; } + if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && + wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE)) { + wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN"); + return 1; + } + if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2"); return 1; @@ -736,6 +745,7 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, struct wpa_blacklist *e; const u8 *ie; struct wpa_ssid *ssid; + int osen; ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); wpa_ie_len = ie ? ie[1] : 0; @@ -743,14 +753,18 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); rsn_ie_len = ie ? ie[1] : 0; + ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); + osen = ie != NULL; + wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' " - "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s%s", + "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s%s%s", i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len), wpa_ie_len, rsn_ie_len, bss->caps, bss->level, wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "", (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) || wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) ? - " p2p" : ""); + " p2p" : "", + osen ? " osen=1" : ""); e = wpa_blacklist_get(wpa_s, bss->bssid); if (e) { @@ -848,7 +862,7 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) continue; - if (!wpa && + if (!osen && !wpa && !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) && !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) { @@ -863,6 +877,12 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, continue; } + if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) { + wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-OSEN network " + "not allowed"); + continue; + } + if (!wpa_supplicant_match_privacy(bss, ssid)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy " "mismatch"); diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 297470dbc..63beaefab 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -757,6 +757,10 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, params.wpa_proto = WPA_PROTO_WPA; wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2, elems.wpa_ie_len + 2); + } else if (elems.osen) { + params.wpa_proto = WPA_PROTO_OSEN; + wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.osen - 2, + elems.osen_len + 2); } else wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group) diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 95ab4af49..14e2c3a5c 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -937,13 +937,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, { struct wpa_ie_data ie; int sel, proto; - const u8 *bss_wpa, *bss_rsn; + const u8 *bss_wpa, *bss_rsn, *bss_osen; if (bss) { bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); + bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); } else - bss_wpa = bss_rsn = NULL; + bss_wpa = bss_rsn = bss_osen = NULL; if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) && wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 && @@ -959,11 +960,22 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, (ie.key_mgmt & ssid->key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0"); proto = WPA_PROTO_WPA; +#ifdef CONFIG_HS20 + } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN)) { + wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN"); + /* TODO: parse OSEN element */ + ie.group_cipher = WPA_CIPHER_CCMP; + ie.pairwise_cipher = WPA_CIPHER_CCMP; + ie.key_mgmt = WPA_KEY_MGMT_OSEN; + proto = WPA_PROTO_OSEN; +#endif /* CONFIG_HS20 */ } else if (bss) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN"); return -1; } else { - if (ssid->proto & WPA_PROTO_RSN) + if (ssid->proto & WPA_PROTO_OSEN) + proto = WPA_PROTO_OSEN; + else if (ssid->proto & WPA_PROTO_RSN) proto = WPA_PROTO_RSN; else proto = WPA_PROTO_WPA; @@ -996,7 +1008,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_s->wpa_proto = proto; wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, - !!(ssid->proto & WPA_PROTO_RSN)); + !!(ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN))); if (bss || !wpa_s->ap_ies_from_associnfo) { if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa, @@ -1067,6 +1079,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, } else if (sel & WPA_KEY_MGMT_WPA_NONE) { wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE"); +#ifdef CONFIG_HS20 + } else if (sel & WPA_KEY_MGMT_OSEN) { + wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN; + wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN"); +#endif /* CONFIG_HS20 */ } else { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select " "authenticated key management type");