const u8 *msk, size_t msk_len,
int *is_pub);
#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_PASN
+
+static int handle_auth_pasn_resp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct rsn_pmksa_cache_entry *pmksa,
+ u16 status);
+#ifdef CONFIG_FILS
+
+static void pasn_fils_auth_resp(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 status,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len);
+
+#endif /* CONFIG_FILS */
+#endif /* CONFIG_PASN */
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int rssi, int from_queue);
struct wpabuf *erp_resp,
const u8 *msk, size_t msk_len)
{
- struct wpabuf *data;
- int pub = 0;
u16 resp;
+ u32 flags = sta->flags;
- sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+ sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
+ WLAN_STA_PENDING_PASN_FILS_ERP);
- if (!sta->fils_pending_cb)
- return;
resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
- data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
- msk, msk_len, &pub);
- if (!data) {
- wpa_printf(MSG_DEBUG,
- "%s: prepare_auth_resp_fils() returned failure",
- __func__);
+
+ if (flags & WLAN_STA_PENDING_FILS_ERP) {
+ struct wpabuf *data;
+ int pub = 0;
+
+ if (!sta->fils_pending_cb)
+ return;
+
+ data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
+ msk, msk_len, &pub);
+ if (!data) {
+ wpa_printf(MSG_DEBUG,
+ "%s: prepare_auth_resp_fils() failure",
+ __func__);
+ }
+ sta->fils_pending_cb(hapd, sta, resp, data, pub);
+#ifdef CONFIG_PASN
+ } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
+ pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
+ msk, msk_len);
+#endif /* CONFIG_PASN */
}
- sta->fils_pending_cb(hapd, sta, resp, data, pub);
}
#endif /* CONFIG_FILS */
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+
+static struct wpabuf * pasn_get_fils_wd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ struct wpabuf *buf = NULL;
+
+ if (!fils->erp_resp) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp");
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ return NULL;
+
+ /* Add the authentication algorithm */
+ wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
+
+ /* Authentication Transaction seq# */
+ wpabuf_put_le16(buf, 2);
+
+ /* Status Code */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ /* Own RSNE */
+ wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
+
+ /* FILS Nonce */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
+ wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN);
+
+ /* FILS Session */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN);
+
+ /* Wrapped Data */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
+ wpabuf_put_buf(buf, fils->erp_resp);
+
+ return buf;
+}
+
+
+static void pasn_fils_auth_resp(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 status,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ u8 pmk[PMK_LEN_MAX];
+ size_t pmk_len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
+ status);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+ if (!pasn->secret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
+ goto fail;
+ }
+
+ if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
+ fils->anonce, FILS_NONCE_LEN);
+
+ ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
+ fils->anonce, NULL, 0, pmk, &pmk_len);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
+ goto fail;
+ }
+
+ ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
+ wpabuf_head(pasn->secret),
+ wpabuf_len(pasn->secret),
+ &sta->pasn->ptk, sta->pasn->akmp,
+ sta->pasn->cipher, WPA_KDK_MAX_LEN);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
+
+ wpabuf_free(pasn->secret);
+ pasn->secret = NULL;
+
+ fils->erp_resp = erp_resp;
+ ret = handle_auth_pasn_resp(hapd, sta, NULL, WLAN_STATUS_SUCCESS);
+ fils->erp_resp = NULL;
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
+ goto fail;
+ }
+
+ fils->state = PASN_FILS_STATE_COMPLETE;
+ return;
+fail:
+ ap_free_sta(hapd, sta);
+}
+
+
+static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
+ struct wpabuf *wd)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsne_data;
+ struct wpabuf *fils_wd;
+ const u8 *data;
+ size_t buf_len;
+ u16 alg, seq, status;
+ int ret;
+
+ if (fils->state != PASN_FILS_STATE_NONE) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
+ return -1;
+ }
+
+ if (!wd) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
+ return -1;
+ }
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%lu",
+ buf_len);
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
+ status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Dropping peer authentication");
+ return -1;
+ }
+
+ data += 6;
+ buf_len -= 6;
+
+ if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
+ return -1;
+ }
+
+ if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
+ !elems.wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
+ return -1;
+ }
+
+ ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
+ return -1;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
+ return -1;
+ }
+
+ if (rsne_data.num_pmkid) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Not expecting PMKID in RSNE");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
+ FILS_NONCE_LEN);
+ os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
+ FILS_SESSION_LEN);
+ os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
+
+#ifdef CONFIG_NO_RADIUS
+ wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
+ return -1;
+#endif /* CONFIG_NO_RADIUS */
+
+ fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!fils_wd) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
+ return -1;
+ }
+
+ if (!sta->eapol_sm)
+ sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
+
+ ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
+ wpabuf_len(fils_wd));
+
+ sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
+
+ fils->state = PASN_FILS_STATE_PENDING_AS;
+
+ /*
+ * Calculate pending PMKID here so that we do not need to maintain a
+ * copy of the EAP-Initiate/Reautt message.
+ */
+ fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
+ fils->erp_pmkid);
+
+ wpabuf_free(fils_wd);
+ return 0;
+}
+
+#endif /* CONFIG_FILS */
+
+
static struct wpabuf * pasn_get_wrapped_data(struct hostapd_data *hapd,
struct sta_info *sta)
{
case WPA_KEY_MGMT_SAE:
#ifdef CONFIG_SAE
return pasn_get_sae_wd(hapd, sta);
+#else /* CONFIG_SAE */
+ wpa_printf(MSG_ERROR,
+ "PASN: SAE: Cannot derive wrapped data");
+ return NULL;
#endif /* CONFIG_SAE */
- /* fall through */
case WPA_KEY_MGMT_FILS_SHA256:
case WPA_KEY_MGMT_FILS_SHA384:
+#ifdef CONFIG_FILS
+ return pasn_get_fils_wd(hapd, sta);
+#endif /* CONFIG_FILS */
+ /* fall through */
case WPA_KEY_MGMT_FT_PSK:
case WPA_KEY_MGMT_FT_IEEE8021X:
case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
struct ieee802_11_elems elems;
struct wpa_ie_data rsn_data;
struct wpa_pasn_params_data pasn_params;
- struct rsn_pmksa_cache_entry *pmksa;
+ struct rsn_pmksa_cache_entry *pmksa = NULL;
struct wpabuf *wrapped_data = NULL, *secret = NULL;
const int *groups = hapd->conf->pasn_groups;
static const int default_groups[] = { 19, 0 };
u16 status = WLAN_STATUS_SUCCESS;
int ret;
+ bool derive_keys;
u32 i;
if (!groups)
goto send_resp;
}
+ derive_keys = true;
if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
wrapped_data = ieee802_11_defrag(&elems,
WLAN_EID_EXTENSION,
}
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ ret = pasn_wd_handle_fils(hapd, sta, wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing FILS wrapped data");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Pending AS response");
+
+ /*
+ * With PASN/FILS, keys can be derived only after a
+ * response from the AS is processed.
+ */
+ derive_keys = false;
+ }
+#endif /* CONFIG_FILS */
}
sta->pasn->wrapped_data_format = pasn_params.wrapped_data_format;
+ ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
+ ((const u8 *) mgmt) + IEEE80211_HDRLEN,
+ len - IEEE80211_HDRLEN, sta->pasn->hash);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ if (!derive_keys) {
+ wpa_printf(MSG_DEBUG, "PASN: Storing secret");
+ sta->pasn->secret = secret;
+ wpabuf_free(wrapped_data);
+ return;
+ }
+
if (rsn_data.num_pmkid) {
wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry");
}
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ if (wrapped_data) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Ignore wrapped data");
+ }
+ }
+#endif /* CONFIG_FILS */
wpabuf_free(wrapped_data);
}